local _ENV = hf_setenv('brnntable',true)

-------------------------------------------------------------
local skynet                           = require "skynet"
local utils                            = require "utils"
local proxypack                        = require "proxypack"
local msgdef                           = require "msgdef"
local pb                               = require "protobuf"
local cjson                            = require "cjson"
local server_def                       = require "server_def"
local util                             = require "util"
local table_def                        = require "table_def"
local sharedata                        = require "skynet.sharedata"
local error_code                       = require "error_code"
local reason                           = require "reason"
local brnn                             = require "niuniu.brnn"
local cocall                           = require "cocall"
local constant                         = require "constant"
local nn_robot                         = require "niuniu.nn_robot"
local system_store                     = require "system_store"
local game_def                         = require "game_def"
local events                           = require "events"
local expand = require("expand") --老游戏功能拓展



local table_insert                     = table.insert
local table_remove                     = table.remove
local table_sort                       = table.sort
local table_unpack                     = table.unpack
local math_floor                       = math.floor
local string_format                    = string.format
local math_random                      = math.random
local math_abs                         = math.abs

local GAME_TIME_LOAD_ROBOT              = 5

local REGISTER_CLIENT_FD               = 0
local OFFLINE_CLIENT_FD                = -1
local ROBOT_CLIENT_FD                   = -2

local MAX_SEAT_NUM                     = 6 --只能坐6个人

local TABLE_STATUS_STRING              = {}

---------------------牌路显示状态--------------------
local TREND_STATUS_WAIT = 1 --休息状态
local TREND_STATUS_BET = 2 -- 下注状态
local TREND_STATUS_END  = 3 -- 结束状态

local TABLE_STATUS = {
     TABLE_STATUS_WAIT                = 1, --等待准备
     TABLE_STATUS_CHECK_START         = 2, --游戏开始
     TABLE_STATUS_BET                 = 3, --开始玩游戏
     TABLE_STATUS_GAMEOVER            = 4, 
     TABLE_STATUS_GAMEOVER_WAIT       = 5,
     TABLE_STATUS_RESTART             = 6,
     TABLE_STATUS_CHANGE_BANKER       = 7, --换庄动画
     TABLE_STATUS_REAL_TIME_PAD_BEGIN = 8,  --下注开始动画    
}

--------------------------客户端阶段-------------------
local CLIENT_PHASE_WAITING_START = 1
local CLIENT_PHASE_WAITING_BET = 2
local CLIENT_PHASE_BETTING = 3
local CLIENT_PHASE_GAMEOVER = 4

local MAX_TREND_LIST_NUM               = 72

local GAME_REAL_TIME_PAD               = 2
local GAME_STATUS_WAIT_TIME            = 1
local GAME_STATUS_BET_TIME             = 15
local GAME_STATUS_GAMEOVER_WAIT_TIME   = 16
local GAME_REAL_TIME_PAD_END           = 2

local GAME_TIME_BET                    = 7
local GAME_TIME_CHANGE_BANKER          = 3  

local BANKER_CHANGE_YES                = 1
local BANKER_CHANGE_NO                 = 2
----------------------------------------------------

local handler = {}
local internal = {}

function init()
    global_configs = nil
    uid_game_session_map             = {} --标记房间所有玩家的clientId 包括观战者的clientId
    player_info_list                 = {}
    seated_position_uid_map          = {} --坐下的玩家的顺序
    noseat_players_list              = {} --无座玩家的映射
    curr_locked_uids                 = {}
    uid_bet_map                      = {}
    card_type_times_map              = {}
    sorted_special_card_type         = {}
    --available_bet_coins_flag_map     = {}
    curr_banker_uid                  = constant.SYSTEM_DO_BANKER_UID 
    bankers_queue                    = {}
    need_change_banker_flag          = false
    BANKER_ACTION                    = { DO_BANKER = 1, UNDO_BANKER = 2 }
    
    self_game_config = nil
    curr_brnn_instance = nil
    curr_round = nil
    
    closing_server                   = false
    stopping_server                 = false         --停止服务器 
    curr_status = nil

    game_start_init_time = nil
    game_start_wait_time = nil
    game_start_bet_time = nil
    game_start_game_over_time = nil
    game_start_banker_time = nil 
    game_start_pad_time = nil 
    game_start_game_over_wait_time = nil
    
    g_game_result_info = nil
    g_bet_batch_list = nil
    game_trend_list                  = {}
    curr_game_trend_index            = 0
    
    robot_manager                    = {}
    
    pre_undo_banker                = {}          
    record_last_player_bet           = 0          --记录上一局真实玩家总下注
    control_player_uid               = nil        --受控玩家的uid
    record_pic_player                = {}         --记录前五局输赢玩家的uid
    record_special_list              = {}         --前20局下注最多的和获胜局数最多的  
    player_avg_bet                   = 0          --记录上一局玩家的下注金额均值
    self_table_type = nil
    self_table_id = nil
    self_table_gid = nil
    self_table_pattern = nil
    self_game_type = nil

    tablesvr_id = tonumber(skynet.getenv "server_id")

    --enter_robot_map = {}
    start_coins_map = {}

    last_banker_info = constant.BR_NN_BANKER_INFO  --上一局庄家的信息                     

    banker_number = 0

    --触发财神驾到的金额
    caishen_coins_map = {}

    is_curr_have_robot = false
    gm_store_coins_add = 0

    check_stop_bet = false

    reduce_award_store = false
    system_result_type = 0 --系统控制类型
    gm_control_uid     = 0 --gm控制玩家uid
    system_money_cost = 0 -- 系统总输赢
    err_result = 0  -- 系统控制结果 0 控制成功  1 系统赢钱 2 随机
    -- 连续投注次数记录
    player_not_bet_num = {}

    robot_last_time = 0 --机器人下一次登录广播时间
    robot_enter_time = {} --机器人登录时间列表
    robot_enter_list = {} -- 机器人登录列表

    hf_set_sentinel_end(_ENV)


end

local function trigger_event(action,...)
    for _, robot_obj in pairs(robot_manager) do
        local f = robot_obj[action]
        if f then
            f(robot_obj, ...)
        end
    end
end

local function set_position(pos,uid)
    seated_position_uid_map[pos] = uid
end

local function clear_position(pos)
    seated_position_uid_map[pos] = false
end

local function init_position()
    for i = 1, MAX_SEAT_NUM do
        table_insert(seated_position_uid_map, false)
    end 
end

local function load_config()
    local attr = {}
    global_configs = nil
    global_configs = setmetatable({},{
        __index = function(t,k) 
            if attr[k] then
                return attr[k]
            else
                local v = sharedata.deepcopy(k)
                attr[k] = v
                return v
            end
        end
    })
    _G.global_configs = global_configs    
end

local function is_banker(uid) 
    return uid == curr_banker_uid
end

local function set_table_status_string()
    TABLE_STATUS_STRING[TABLE_STATUS.TABLE_STATUS_WAIT]          = "wait"
    TABLE_STATUS_STRING[TABLE_STATUS.TABLE_STATUS_CHECK_START]   = "check start"
    TABLE_STATUS_STRING[TABLE_STATUS.TABLE_STATUS_BET]           = "bet"
    TABLE_STATUS_STRING[TABLE_STATUS.TABLE_STATUS_GAMEOVER]      = "game over"
    TABLE_STATUS_STRING[TABLE_STATUS.TABLE_STATUS_GAMEOVER_WAIT] = "game over wait"
    TABLE_STATUS_STRING[TABLE_STATUS.TABLE_STATUS_RESTART]       = "restart"
end

local function rand_robot_name()
    local names_library = global_configs.names_library
    local name = (names_library and #names_library > 1) and names_library[math_random(1,#names_library)] or '幸运之星'
    return name
end

local function send_to_gateway(uid, client_fd, ...)
    if not client_fd then
        return
    end
    if client_fd <= 0 then
        return
    end
    return utils.send_to_gateway(0, uid, client_fd, ...)
end

local function is_robot(uid)
    if uid == constant.SYSTEM_DO_BANKER_UID then
        return true
    end

    return robot_manager[uid] and true
end


--把输赢发送到好友服(平台游戏概况)
local function sendLoseWinToFriendServer(system_lose_win)
    if system_lose_win == 0 then return end            
    R().friendsvr(1):send('.info_mgr', 'set_room_summary', self_table_type, {table_type = self_table_type, lose_win = system_lose_win})
end


--把当前庄发送到好友服(实时游戏数据)
local function sendBankerToFriendServer()           

    local robot = 0
    if is_robot(curr_banker_uid) then 
        robot = 1
    end
    local data = {  
                    table_type = self_table_type, 
                    banker_id = curr_banker_uid,
                    is_robot = robot,
                }
    dbglog("sendBankerToFriendServer:", data)   
    R().friendsvr(1):send('.info_mgr', 'set_room_banker', self_table_type, data)
end 

--[[
local function call_can_take_compensation(uid)
    local ok, given, ret = R().basesvr({ key = uid }):call(".msg_handler", "can_take_compensation", uid)
    if not ok then
        errlog(string_format("failed to call basesvr can_take_compensation uid(%d)", uid))
        return false
    end

    if not given then
        dbglog(string_format("give is nil uid(%d)", uid))
        return false
    end

    return {
        left_times = ret,
        compensation_coins = global_configs.value.BASE_COMPENSATION_COINS
    }
end
--]]

local function have_player()
    for uid,_ in pairs(player_info_list) do
        if not is_robot(uid) then
            return true
        end
    end
    return false
end

local function get_seated_robot_num()
    local robot_num = 0

    for _, uid in pairs(seated_position_uid_map) do
        if is_robot(uid) then
            robot_num = robot_num + 1
        end
    end

    return robot_num
end

local function robot_num()
    local robot_num = 0
    for k,v in pairs(robot_manager) do
        robot_num = robot_num + 1
    end

    return robot_num
end

local function get_real_player_seated_num()
    local num = 0

    for position, uid in pairs(seated_position_uid_map) do
        if uid and not is_robot(uid) then
            num = num + 1
        end
    end

    return num
end

--是否要换庄
local function set_need_change_banker_flag(flag)
    need_change_banker_flag = flag
end

local function get_need_change_banker_flag()
    return need_change_banker_flag
end

--[[
local function can_take_compensation()
    local tasks = {}

    for position, uid in pairs(seated_position_uid_map) do
        if uid then
            if not is_robot(uid) then
                table_insert(tasks, { f = call_can_take_compensation, id = uid, params = { uid } })
            end
        end
    end
    
    local ok, results = cocall(COCALL_TIMEOUT, tasks)
    if not ok then
        errlog(string_format("failed to cocall results(%s)", tostring_r(results)))
        return false
    end

    for uid, ret in pairs(results) do
        if ret then
            local rsp = {
                left_compensation_times = ret.left_times,
                compensation_coins = ret.compensation_coins,
            }

            send_to_gateway(uid, uid_game_session_map[uid], "hall.NTF_COMPENSATION", rsp)

            billlog({ 
                op = "bankrupt_register", 
                uid = uid, 
                game_type = self_game_type, 
                table_type = self_table_type, 
                ret = reason.BANKRUPT_REGISTER,
            })
        end
    end

    return true
end

local function notify_take_compensation(uid)
    local ret = call_can_take_compensation(uid)
    if not ret then
        return false
    end

    local rsp = {
        left_compensation_times = ret.left_times,
        compensation_coins = ret.compensation_coins,
    }

    send_to_gateway(uid, uid_game_session_map[uid], "hall.NTF_COMPENSATION", rsp)
end
--]]

local function notify_others(action, excepted_uid, msg)
    --先广播给桌子上的人
    for uid,  fd in pairs(uid_game_session_map) do
        if uid ~= excepted_uid then
            send_to_gateway(uid, fd, action, msg)
        end
    end
end

local function notify_all(action, msg)
    return notify_others(action, nil, msg)
end

local function get_rsp_player_info(player_info)
    return { 
        uid = player_info.uid, 
        name = player_info.name, 
        coins = player_info.coins, 
        icon = player_info.icon, 
        position = player_info.position, 
        sex = player_info.sex,
        vip_level = player_info.vip_level,
        icon_border = player_info.icon_border,
        win_count = player_info.win_count or 0,
        total_bet = player_info.total_bet or 0,
        play_count = player_info.play_count or 0,
     }
end

function check_robot_ntf_enter(curr_time)
    if robot_last_time and curr_time < robot_last_time then return end
    
    --CD时间
    for uid,v in pairs(robot_enter_time) do
        if v < curr_time - 60*30 then
            robot_enter_time[uid] = nil 
        end
    end

    -- dbglog(robot_enter_list,robot_enter_time)

    local enter_robot_id
    local count = #robot_enter_list
    for i = 1,count do
        local uid = table_remove(robot_enter_list)
        if not robot_enter_time[uid] then
            enter_robot_id = uid 
            break
        end
    end

    if not enter_robot_id then
        -- dbglog("enter_robot_id:",enter_robot_id)
        return 
    end

    local play_effect = false
    local player_info = player_info_list[enter_robot_id]

    if not player_info then
        dbglog("enter_robot_id:",enter_robot_id)
        return 
    end
    dbglog("player_info:",player_info)
    robot_enter_time[enter_robot_id] = curr_time
    local enter_word = ""
    local vip_level_conf = utils.getDataBykv(global_configs.vip,"level",player_info.vip_level or 0)
    if vip_level_conf and vip_level_conf.privilege[game_def.VIP_PRIVILEGE_TYPE_SIX] then
        robot_last_time = curr_time + math_random(60,120)
        play_effect = true
        enter_word = vip_level_conf.enter_word or ""
        dbglog("NTF_PLAYER_ENTER")
        notify_all("brnn.NTF_PLAYER_ENTER", {play_effect = play_effect,enter_word = enter_word,player = get_rsp_player_info(player_info)})
        dbglog(enter_word,enter_robot_id)
    end
end

local function get_extra_bill_info(uid)
    local t = { game_type = self_game_type, table_type = self_table_type }
    local player_info = player_info_list[uid]

    if not player_info then
        return t
    end

    t.client_version = player_info.client_version
    t.channel = player_info.channel
    t.cur_channel = player_info.cur_channel
    t.device_id = player_info.device_id
    t.device_brand = player_info.device_brand
    t.os_system = player_info.os_system
    t.platform = player_info.platform
        
    return t
end

local function get_player_num()
    local num = 0

    for _, v in ipairs(seated_position_uid_map) do
        if v then
            num = num + 1
        end
    end

    return num + #noseat_players_list
end

local function get_player_num_without_robot()
    local num = 0
    for uid, _ in pairs(player_info_list) do
        if not is_robot(uid) then
            num = num + 1
        end
    end

    return num
end

local function watch_session(game_session, uid, observing)
    if game_session <= 0 then
        return
    end

    local gateway_id = game_session >> 31
    local request

    if observing then
        request = "observe_fd"
    else
        request = "unobserve_fd"
    end

    R().gateway(gateway_id):send(".watchdog", "tablesvr", request, R().get_source(), game_session, uid)
end

local function is_game_session_correct(uid, game_session)
    if uid_game_session_map[uid] ~= game_session then
        errlog("is_game_session_correct ", uid, uid_game_session_map[uid], game_session)
        return false
    end

    return true
end

local function is_game_status_correct(uid, correct_game_status)
    if curr_status ~= correct_game_status then
        return false
    end

    return true
end

local function add_to_noseat(uid)
    table_insert(noseat_players_list, uid)
    return true
end

local function system_do_banker(uid)
    return uid == constant.SYSTEM_DO_BANKER_UID
end

local function remove_from_noseat(uid)
    local noseat_idx

    for i, suid in ipairs(noseat_players_list) do
        if suid == uid then
            noseat_idx = i
            break
        end
    end

    if noseat_idx then
        table_remove(noseat_players_list, noseat_idx)
    end
end

function get_own_coins(uid)
    local player_info = player_info_list[uid]
    return player_info.coins
end

function sit_down_coins_meet_condition(uid, game_session,pos)
    if is_banker(uid) then
        return false, error_code.BANKER_NOT_ALLOW_SIT
    end

    --特殊位置坐下没有金钱限制
    if pos == brnn.RICH_SEAT_SIDE or pos == brnn.LUCK_SEAT_SIDE then
        return true
    end

    local own_coins = get_own_coins(uid)

    local roomdata = global_configs.roomdata[self_table_type]
    local sit_coins_limit = roomdata.sit_coins_limit or 10000

    if own_coins < sit_coins_limit then
        return false, error_code.CANT_SITDOWN_NO_MONEY, sit_coins_limit
    end

    return true
end

--真实玩家列表
local function get_player_uid_list()
    local player_list = {}
    for uid, player_info in pairs(player_info_list) do
        if not is_robot(uid) then
            table_insert(player_list,uid)
        end
    end

    return player_list
end

--在无座位的机器人中随机取num个
local function get_noseat_robot_uid(num)
    local no_seat_robot_ids = {}
    local random_uid = {}
    for _,uid in pairs(noseat_players_list) do
        if is_robot(uid) then
            local player_info = assert(player_info_list[uid])
            if player_info.coins > 100 then  --携带金币>100才能入座
                table_insert(no_seat_robot_ids,uid) 
            end
        end
    end
    for i = 1, num do
        if #no_seat_robot_ids > 0 then
            local random_index = math_random(1,#no_seat_robot_ids)
            table_insert(random_uid,no_seat_robot_ids[random_index])
            table_remove(no_seat_robot_ids,random_index)
        end
    end

    return random_uid
end

local function in_bankers_queue(uid)
    for k, v in pairs(bankers_queue) do
        if v == uid then
            dbglog(string_format("uid(%d) is banker already", uid))
            return true
        end
    end

    return false
end

local function deal_stand_up(player_info, position)
    local uid = player_info.uid

    if seated_position_uid_map[player_info.position] == false then
        errlog(string_format("uid(%d) not in position(%d) UP_FAIL_NOT_HAVE_SEAT", uid, player_info.position))
        return false, error_code.UP_FAIL_NOT_HAVE_SEAT
    end

    if player_info.position ~= position then
        errlog(string_format("uid(%d) player_info.position(%d) not in position(%d) THE_POSITION_NOT_MATCH", 
            uid, player_info.position, position))
        return false, error_code.THE_POSITION_NOT_MATCH
    end

    if seated_position_uid_map[position] ~= uid then
        errlog(string_format("uid(%d) not in position(%d) THE_POSITION_NOT_MATCH", uid, position))
        return false, error_code.THE_POSITION_NOT_MATCH
    end

    notify_all("brnn.NTF_STANDUP", { uid = uid })

    clear_position(position)
    player_info.position = nil    
    add_to_noseat(uid)

    return true
end

local function deal_sit_down(uid, pos)
    local ok, ret, sitdown_coin = sit_down_coins_meet_condition(uid, game_session,pos)
    if not ok then
        return false, ret, sitdown_coin
    end

    if seated_position_uid_map[pos] ~= false then
        if not is_robot(uid) then
            errlog(string_format("uid(%d) SEAT_IS_EMPLOY", uid))
        end
        return false, error_code.SEAT_IS_EMPLOY
    end

    local player_info = player_info_list[uid]

    if not player_info then
        if not is_robot(uid) then
            errlog(string_format("uid(%d) PLAYER_HAS_NO_TABLE", uid))
        end
        return false, error_code.PLAYER_HAS_NO_TABLE
    end

    if player_info.position then
        if not is_robot(uid) then
            errlog(string_format("uid(%d) SEAT_FAIL_HAVE_SEAT", uid))
        end
        return false, error_code.SEAT_FAIL_HAVE_SEAT
    end

    --assert(remove_from_noseat(uid))
    remove_from_noseat(uid)
    set_position(pos,uid)
    player_info.position = pos

    notify_all("brnn.NTF_SITDOWN", { player = get_rsp_player_info(player_info) })
    return true
end

local function lock_one_player(uid, table_gid)
    if is_robot(uid) then return end
    local ok, succ = R().exdbsvr(1):call(".tlock_mgr", "set_on_table", uid, table_gid, table_gid)
    if not ok then
        errlog(string_format("uid(%d) table_gid(%d) failed to set_on_table", uid, table_gid))
        return false
    end

    if not succ then
        return false
    end

    curr_locked_uids[uid] = true
    return true
end

--玩这实时输赢op
function realTimeWinLose(uid)
    if is_robot(uid) then return end
    local player_info = player_info_list[uid]
    if not player_info.enter_time then 
        errlog("__________player_info.enter_time__是空的____", uid, player_info)
        return 
    end       
    local table_gid = player_info.enter_time .. "_" .. self_table_id .."_"..uid
    local leave_time = util:get_now_time()  --真正离开游戏了 
    if player_info.all_win_lose == 0 and player_info.all_free == 0 then 
        --没产生流水就不记录了
        return
    end
    local data = {
        op = "user_leave_game",
        uid = uid,
        table_gid = table_gid, --唯一标记
        table_type = self_table_type,
        name = player_info.name,        
        enter_coins = player_info.enter_coins, --进入时身上金币
        enter_safe_coins = player_info.enter_safe_coins, --进入时保险箱金币 
        enter_time = player_info.enter_time, --进入时间
        leave_time = leave_time, --离开时间
        leave_coins = player_info.coins, --离开时身上金币
        leave_safe_coins = player_info.safe_box, --离开时保险箱金币
        win_lose = player_info.all_win_lose, --在玩游戏内产生的输赢（
        free = player_info.all_free, --玩游戏交上的台费
    }
    dbglog("_______user_leave_game_____",  data)
    billlog(data)
end

local function unlock_one_player(uid, table_gid)
    if is_robot(uid) then return end
    R().exdbsvr(1):send(".tlock_mgr", "unset_on_table", uid, self_table_gid)
    curr_locked_uids[uid] = nil
end

local function clear_special_pos_data(uid)
    for _,special_list in pairs(record_special_list) do
        if special_list[uid] then
            special_list[uid] = nil
        end
    end 
end

local function clear_and_unlock_offline_player(uid)
--    dbglog(string_format("uid(%d) clear offlined player", uid))
    unlock_one_player(uid, self_table_gid)
    realTimeWinLose(uid)
    local player_info = assert(player_info_list[uid])

    if player_info.position then
        deal_stand_up(player_info, player_info.position)
    end

    uid_game_session_map[uid] = nil
    player_info_list[uid] = nil
    start_coins_map[uid]  = nil
    player_not_bet_num[uid] = nil
    clear_special_pos_data(uid)
    remove_from_noseat(uid)
    --assert(remove_from_noseat(uid))
end

local function get_player_enter_data(uid)
    local ok, base_data = R().basesvr{ key = uid }:call(".msg_handler", "get_base_data", uid)
    if not ok then
        errlog(string_format("uid(%d) call basesvr get_base_data error", uid))
        return
    end


    local ok, enter_data = R().hallsvr{ key = uid }:call(".msg_handler", "get_enter_data", uid)
    if not ok then
        errlog(string_format("uid(%d) call hallsvr get_enter_data error", uid))
        enter_data = {}
    end


    dbglog(string_format("base_data(%s) enter_data(%s)", tostring_r(base_data), tostring_r(enter_data)))

    local player_info = { 
        uid = base_data.uid, 
        name = enter_data.name or "", 
        coins = base_data.coins, 
        icon = enter_data.icon or "", 
        sex = enter_data.sex, 
        vip_level = base_data.vip_level or 0,
        icon_border = enter_data.icon_border,
        safe_box = base_data.safe_box,
     }



    --if enter_data.name ~= nil and enter_data.name ~= "" then
    --  player_info.name = enter_data.name 
    --end

    --if player_info.name == nil then
    --  player_info.name = ""
    --end

    return player_info
end

local function get_rate_list()
    local rate_list = {}

    for type, times in pairs(card_type_times_map) do
        table_insert(rate_list, { type = type, times = times })
    end 

    -- dbglog(string_format("rate_list(%s)", tostring_r(rate_list)))
    return rate_list
end

local function get_my_bet_list(uid)
    local tmp_my_list = curr_brnn_instance:get_my_bet_list(uid)
    local my_bet_list = {}

    if tmp_my_list then
        for side, bet_coins in pairs(tmp_my_list) do
            table_insert(my_bet_list, { side = side, bet_coins = bet_coins })
        end
    end

    return my_bet_list
end

local function get_all_bet_list()
    local tmp_all_list = curr_brnn_instance:get_all_bet_list()
    local all_bet_list = {}

    for side, bet_coins in pairs(tmp_all_list) do
        table_insert(all_bet_list, { side = side, bet_coins = bet_coins })
    end

    return all_bet_list
end

local function get_rsp_player_info_list(luck_uid,rich_uid)
    local rsp_list = {}

    for uid, player_info in pairs(player_info_list) do
        if uid ~= luck_uid and uid ~= rich_uid then
            local rsp_player_info = get_rsp_player_info(player_info)
            table_insert(rsp_list, rsp_player_info)
        end
    end

    return rsp_list
end

--[[
local function get_rsp_seated_info_list()
    local rsp_list = {}
    
    for position, uid in pairs(seated_position_uid_map) do
        if uid then
            local play_info = player_info_list[uid]
            local rsp_player_info = get_rsp_player_info(player_info)
            table_insert(rsp_list, rsp_player_info)
        end
    end

    return rsp_list 
end
--]]

local function get_seated_list()
    local seated_uid_list = {}

    for position, uid in pairs(seated_position_uid_map) do
        if uid then
            local play_info = player_info_list[uid]
            --特殊情况玩家已经不在列表中，位置信息还存在，删除位置信息
            if play_info then
                table_insert(seated_uid_list, get_rsp_player_info(play_info))
            else
                errlog("get_seated_list play_info nill uid: ",uid,"position:",position)
                clear_position(position)
            end
        end
    end

    return seated_uid_list
end

local function get_banker_queue_info()
    local banker_info = {}
    local banker_list = {}

    if system_do_banker(curr_banker_uid) then
        local name = rand_robot_name()
        local info = {uid = constant.BR_NN_BANKER_INFO.uid,name = name,icon = constant.BR_NN_BANKER_INFO.icon}
        table_insert(banker_list,info)
    elseif player_info_list[curr_banker_uid] then
        table_insert(banker_list, get_rsp_player_info(player_info_list[curr_banker_uid]))
    end
    
    for _, uid in pairs(bankers_queue) do
        if player_info_list[uid] then
            table_insert(banker_list, get_rsp_player_info(player_info_list[uid]))
        end
    end

    banker_info.banker_list = banker_list
    banker_info.system_do_banker = system_do_banker(curr_banker_uid)

    return banker_info
end

local function get_betting_list(betting_list,coins)
    local list
    local bet_list

    if betting_list then
        for _, v in pairs(betting_list) do
            local range = utils.str_split(v.coins_range,'-')
            if tonumber(range[1]) and coins >= tonumber(range[1]) then
                if tonumber(range[2]) then
                    if coins < tonumber(range[2]) then
                        list = v.bet_list
                        break
                    end
                else
                    list = v.bet_list
                    break
                end
            end  
        end
    end

    if list then
        bet_list = {}
        for k, v in pairs(list) do  
            bet_list[k] = v
        end
    end

    --print("========list=====",coins,tostring_r(list))
 
    return bet_list
end

local function get_client_status_and_left_time()
    local next_status_time
    local curr_time = util.get_now_time()
    local left_time = 0
    local client_status = 0  
    local status_time = {}
    table_insert(status_time,GAME_STATUS_WAIT_TIME)
    table_insert(status_time,GAME_STATUS_BET_TIME - GAME_REAL_TIME_PAD)
    table_insert(status_time,GAME_STATUS_GAMEOVER_WAIT_TIME + GAME_REAL_TIME_PAD)

    if curr_status == TABLE_STATUS.TABLE_STATUS_WAIT or curr_status == TABLE_STATUS.TABLE_STATUS_CHECK_START then
        --等待开始中，则没有gamestatus
        client_status = TREND_STATUS_WAIT
        next_status_time = game_start_wait_time + GAME_STATUS_WAIT_TIME + GAME_TIME_CHANGE_BANKER + GAME_REAL_TIME_PAD
        left_time = next_status_time - curr_time
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_RESTART then
        client_status = TREND_STATUS_WAIT
        left_time = GAME_STATUS_WAIT_TIME + GAME_TIME_CHANGE_BANKER + GAME_REAL_TIME_PAD
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_CHANGE_BANKER then
        client_status = TREND_STATUS_WAIT
        left_time = game_start_banker_time + GAME_TIME_CHANGE_BANKER + GAME_REAL_TIME_PAD - curr_time
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_REAL_TIME_PAD_BEGIN then
        client_status = TREND_STATUS_WAIT
        left_time = game_start_pad_time + GAME_REAL_TIME_PAD - curr_time
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_BET then
        client_status = TREND_STATUS_BET
        next_status_time = game_start_bet_time + GAME_STATUS_BET_TIME
        left_time = next_status_time - curr_time
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_GAMEOVER then
        client_status = TREND_STATUS_END
        left_time = game_start_game_over_time + GAME_REAL_TIME_PAD_END + GAME_STATUS_GAMEOVER_WAIT_TIME
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_GAMEOVER_WAIT then
        --结算时间
        client_status = TREND_STATUS_END
        next_status_time = game_start_game_over_wait_time + GAME_STATUS_GAMEOVER_WAIT_TIME
        left_time = next_status_time - curr_time
    else
        errlog('unknown status...',curr_status)
    end

    return client_status,left_time,status_time
end

local function get_enter_info(uid)
    local next_status_time
    local curr_game_status = {}
    local curr_time = util.get_now_time()
    local left_time = 0

    if curr_status == TABLE_STATUS.TABLE_STATUS_WAIT or curr_status == TABLE_STATUS.TABLE_STATUS_CHECK_START then
        curr_game_status.curr_status = CLIENT_PHASE_WAITING_START
        next_status_time = game_start_wait_time + GAME_STATUS_WAIT_TIME + GAME_TIME_CHANGE_BANKER 
        left_time = next_status_time - curr_time
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_RESTART  then   
        curr_game_status.curr_status = CLIENT_PHASE_WAITING_START 
        left_time = GAME_STATUS_WAIT_TIME + GAME_TIME_CHANGE_BANKER 
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_CHANGE_BANKER then
        curr_game_status.curr_status = CLIENT_PHASE_WAITING_START
        left_time = game_start_banker_time + GAME_TIME_CHANGE_BANKER - curr_time
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_REAL_TIME_PAD_BEGIN then
        curr_game_status.curr_status = CLIENT_PHASE_WAITING_BET
        left_time = game_start_pad_time + GAME_REAL_TIME_PAD - curr_time
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_BET then
        curr_game_status.curr_status = CLIENT_PHASE_BETTING
        next_status_time = game_start_bet_time + GAME_STATUS_BET_TIME
        curr_game_status.my_bet_list = get_my_bet_list(uid)
        curr_game_status.all_bet_list = get_all_bet_list()
        left_time = next_status_time - curr_time
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_GAMEOVER then
        curr_game_status.curr_status = CLIENT_PHASE_BETTING
        curr_game_status.my_bet_list = get_my_bet_list(uid)
        curr_game_status.all_bet_list = get_all_bet_list()
        left_time = 0
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_GAMEOVER_WAIT then
        curr_game_status.curr_status = CLIENT_PHASE_GAMEOVER
        curr_game_status.my_bet_list = get_my_bet_list(uid)
        curr_game_status.all_bet_list = get_all_bet_list()
        next_status_time = game_start_game_over_wait_time + GAME_STATUS_GAMEOVER_WAIT_TIME
        curr_game_status.game_result = g_game_result_info
        left_time = next_status_time - curr_time    
    else
        errlog(string_format("unknown status(%d)", curr_status))
    end

    if left_time < 0 then 
        left_time = 0 
    end

    local bet_list = global_configs.bet_list.brnn_bet_list
    local roomdata = global_configs.roomdata[self_table_type]

    local min_bet = roomdata.min_bet or 0

    if self_game_type == table_def.GAME_TYPE_TEN_BR_NN then
        bet_list = global_configs.bet_list.brnn_ten_bet_list
        --min_bet = global_configs.bet_list.brnn_ten_min_bet
    end

    local player_info = assert(player_info_list[uid])
    if not player_info.available_betting_list then
        local betting_list = constant.BR_NN_AVAILABLE_BET_COINS_LIST
        
        local available_betting_list = get_betting_list(bet_list,player_info.coins) or betting_list
        player_info.available_betting_list = available_betting_list
    end

    -- dbglog(string_format("game_trend_list(%s)", tostring_r(game_trend_list)))
    --local roomdata = global_configs.roomdata[self_table_type]
    local max_time = 3
    if self_game_type == table_def.GAME_TYPE_TEN_BR_NN then
        max_time = 10
    end
   -- dbglog("max_time:",max_time)
    --local roomdata = global_configs.roomdata[self_table_type]
    local sit_coins_limit = roomdata.sit_coins_limit or 10000
    local min_banker_coins = roomdata.min_banker_coins or 1500000

    --获取剩余可下注金币
    local total_bet_coins,left_bet_coins
    if curr_brnn_instance then
        total_bet_coins,left_bet_coins = curr_brnn_instance:get_bet_info(self_game_type)
    end
    local config ={
        person_limit_min = 0,
        person_limit_max = 0,
    }
    if roomdata.person_limit then
        config.person_limit_min = roomdata.person_limit[1] or 0
        config.person_limit_max = roomdata.person_limit[2] or 0
    end  
    local enter_info = { 
        --player_info_list = get_rsp_player_info_list(), 
        banker_info = get_banker_queue_info(),
        seated_list = get_seated_list(),
        available_bet_list = player_info.available_betting_list, 
        rate_list = get_rate_list(), 
        trend_list = game_trend_list,
        game_status = curr_game_status,         
        left_time = left_time, 
        fee_percent = roomdata.cost or 0,
        do_banker_coins = min_banker_coins,
        sitdown_coins = sit_coins_limit,
        max_time    = max_time,
        bet_need_coins = min_bet,
        curr_total_bet_coins = total_bet_coins,
        curr_left_bet_coins = left_bet_coins,
        config = config,
     }

    return { 
        game_type = self_game_type, 
        table_type = self_table_type, 
        brnn_enter_info = enter_info, 
        name = roomdata.name,
     }
end

local function deal_enter(uid, client_fd, msg)
    dbglog(string_format("uid(%d) client_fd(%d) enter", uid, client_fd))

    if client_fd == ROBOT_CLIENT_FD then
       -- enter_robot_map[uid] = true
        return false
    end

    if not uid_game_session_map[uid] then
        errlog(string_format("uid(%d) had not been registerd", uid))
        return false, -431
    end

    local roomdata = self_game_config
    if not roomdata then
        errlog("unkown table type!!!!",self_table_type)
        return false,-1
    end

    local data = get_player_enter_data(uid)
    if not data then
        errlog(uid,'failed to get_player_enter_data')
        return false,-2
    end


    local player_info = player_info_list[uid]

    if player_info then --玩家如果已经再房间内那么直接那么直接刷新一下玩家数据 这个分支可能是玩家短线重连
        player_info.name = data.name ~= "" and data.name or player_info.name
        player_info.icon = data.icon ~= "" and data.icon or player_info.icon
        player_info.coins = data.coins
        player_info.vip_level = data.vip_level
        player_info.icon_border = data.icon_border
        player_info.win_count = player_info.win_count or 0
        player_info.total_bet = player_info.total_bet or 0
        player_info.play_count = player_info.play_count or 0  --玩家的玩牌局数
        player_info.safe_box = data.safe_box

        if is_banker(uid) then
            set_need_change_banker_flag(false)
            pre_undo_banker = {}
        end

    else --之前没有再房间内也就是首次进入房间
        if get_player_num() >= table_def.game_player_num[self_game_type] then
            return false, error_code.CANNOT_ENTER_ROOM_FULL
        end
        --已经进入过其他房间了
        if not lock_one_player(uid,self_table_gid) then
            errlog(uid,'failed to lock player,you may have been in other table this_table_gid:',self_table_gid)
            return false,error_code.CANNOT_ENTER_FTABLE_LOCKED
        end
        player_info = data
        player_info.init_coins = player_info.coins
        player_info_list[uid] = player_info
        player_info.enter_coins = data.coins
        player_info.enter_time = os.time()
        player_info.enter_safe_coins = data.safe_box
        player_info.all_win_lose = 0
        player_info.total_coins = 0
        player_info.all_free = 0
        player_info.all_produce = 0
        player_info.all_bet = 0

    end
    player_info.os_system = data.os_system
    player_info.platform = data.platform
    uid_game_session_map[uid] = client_fd

    player_info.client_version = msg.client_version
    player_info.channel = msg.channel
    player_info.cur_channel = msg.cur_channel
    player_info.device_id = msg.device_id
    player_info.device_brand = msg.device_brand

    local rsp_enter_info = get_enter_info(uid)
    return true, rsp_enter_info
end

local function get_random_robot_uid()
    local robot_ids = {}
    for uid,v in pairs(player_info_list) do
        if is_robot(uid) and robot_manager[uid] then
            table_insert(robot_ids,uid) 
        end
    end

    if #robot_ids > 0 then
        local random_index = math_random(1,#robot_ids)
        return robot_ids[random_index]
    end

    return nil
end

local function coins_meet_banker_condition(uid)
    if system_do_banker(uid) then
        return true
    end

    local player_info = player_info_list[uid]
    if not player_info then
        return false
    end
    local roomdata = global_configs.roomdata[self_table_type]
    local min_banker_coins = roomdata.min_banker_coins or 1500000

    if player_info.coins >= min_banker_coins then
        return true
    end

    return false
end

local function force_set_robot_banker(uid)
    local player_info = player_info_list[uid]
    if not player_info then
        return false
    end

    if not is_robot(uid) then
        return false
    end

    local roomdata = global_configs.roomdata[self_table_type]
    local robot_type = roomdata.robot_type or 'brnn_normal'
    local robot_control  = global_configs.robot[robot_type] or {}
    local robot_type_list = robot_control.robot_type_list or {}
    local coins_range = (robot_type_list[6] or {}).coins_range
    local coins_limit = utils.str_split(coins_range,',') or {}
    local min_banker_coins = math_random(tonumber(coins_limit[1]) or 0,tonumber(coins_limit[2]) or 0)
    if player_info.coins < min_banker_coins then
        player_info.coins = min_banker_coins
        R().basesvr{key=uid}:call('.msg_handler','set_coins',uid,min_banker_coins,reason.FORCE_ROBOT_BANKER)
    end

    return true
end

local function set_current_banker(uid)
    print("set_current_banker====",uid)
    curr_banker_uid = uid
    local player_info = player_info_list[uid]
    if player_info and player_info.position then
        handler.REQ_STANDUP(uid, {position = player_info.position}, uid_game_session_map[uid])
    end

    sendBankerToFriendServer()    
end

local function get_bankers_queue_number()
    return #bankers_queue
end



local function get_banker_round(coins)
    local roomdata = global_configs.roomdata[self_table_type] or {}
    local robot_type = roomdata.robot_type or "brnn_normal"
    local brnn_banker_control = global_configs.robot_banker_control[robot_type]
    local obj = brnn_banker_control.banker_round[1]
    for _,round_obj in pairs(brnn_banker_control.banker_round) do
        if round_obj.min <= coins and round_obj.max >= coins then
            obj = round_obj
            break
        end
    end

    local range = utils.str_split(obj.round_range,'-')
    local round = math_random(tonumber(range[1]),tonumber(range[2]))
    dbglog("get_banker_round round:",round)
    return round
end

--1先找上庄列表的当庄
--2找不到上庄列表的随机一个机器人
--3没开放机器人的时候系统当庄
local function select_banker()
    while get_bankers_queue_number() > 0 do 
        local uid = table_remove(bankers_queue,1)
        if coins_meet_banker_condition(uid) then
            set_current_banker(uid)
            return true
        end
    end

    -- local uid = get_random_robot_uid()
    -- if force_set_robot_banker(uid) then
    --     --未进入上庄列表的机器人上庄，设置初始round
    --     local round = get_banker_round(player_info_list[uid].coins)
    --     robot_manager[uid]['on_do_banker'](robot_manager[uid],round)
    --     set_current_banker(uid)
    --     return true
    -- end
    set_current_banker(constant.SYSTEM_DO_BANKER_UID)

    return true
end

local function set_banker_by_turn()
    --目前庄家没申请下庄,钱也足够的情况
    if curr_banker_uid ~= constant.SYSTEM_DO_BANKER_UID and coins_meet_banker_condition(curr_banker_uid)
      and not utils.is_in_table(pre_undo_banker,curr_banker_uid) then
        return
    end

    if get_need_change_banker_flag() then
        set_need_change_banker_flag(false)
        return select_banker()
    end

    return select_banker()
end


local function player_num_meet_condition()
    -- local num = get_player_num()

    -- if num == 0 then
    --     return false
    -- end
    --[[    
    --只有1人且为庄也要开局
    elseif num == 1 then
        for uid, _ in pairs(uid_game_session_map) do
            if is_banker(uid) then
                return false
            end
        end
    end
    --]]

    return true
end
--[[
function init_available_bet_list()
    for k, v in pairs(constant.BR_NN_AVAILABLE_BET_COINS_LIST) do 
        available_bet_coins_flag_map[v] = true
    end
end--]]


local function get_total_coins(robot_type)
    local ok,succ,total_coins = R().robotmgr(1):call('.msg_handler','get_total_coins',robot_type)
    if not ok then
        errlog("get_total_coins fail because ok is nil")
        return
    end
    
    return succ,total_coins
end

local function meet_start_condition()
   if curr_brnn_instance then
        errlog("curr_brnn_instance exists")
        return false
    end

    if not player_num_meet_condition() then
        errlog("player_num_meet_condition ")
        return false
    end

    set_banker_by_turn() 
--[[    
        notify_all("brnn.NTF_BANKER_ACTION", { 
        action = BANKER_ACTION.DO_BANKER,
        uid = curr_banker_uid,
        banker_info = get_banker_queue_info(),
     })
--]]     

    local instance = brnn:new()
    instance:init(card_type_times_map,sorted_special_card_type,self_table_type)
    instance:set_banker(curr_banker_uid,is_robot(curr_banker_uid))

    if system_do_banker(curr_banker_uid) then
        instance:init_player_coins(curr_banker_uid, -1)
    else
        local player_info = player_info_list[curr_banker_uid]
        instance:init_player_coins(curr_banker_uid, player_info.coins)
    end

    instance:deal()
    --比较输赢的时候再设置系统庄家的牌，减少系统库存带来的误差
    --[[if system_do_banker(curr_banker_uid) then
        instance:set_system_banker_cards(curr_banker_uid,self_game_type,self_table_id)
    end
  --]]
    dbglog("now start the game...")
    curr_brnn_instance = instance
    return true
end

local function reduce_coins(uid, money, reason, ...)
    --local ok, succ, ret = R().basesvr({ key = uid }):call(".msg_handler", "reduce_coins", uid, money, reason, ...)
    local ok, succ, ret = R().basesvr({ key = uid }):call(".msg_handler", "reduce_coins_to_empty", uid, money, reason, ...)
    
    if not ok then
        errlog(string_format("uid(%d) call basesvr reduce_coins error", uid))
        return false
    end

    if not succ then
        errlog(string_format("uid(%d) basesvr reduce_coins succ == false error", uid))
        return false
    end

    R().basesvr{key=uid}:send('.msg_handler','add_lose_coins', uid, money)

    return true, { curr = ret.curr }
end

local function add_coins(uid, money, reason, ...)

    local ok, succ, ret = R().basesvr({ key = uid }):call(".msg_handler", "add_coins", uid, money, reason, ...)
    if not ok then
        errlog(string_format("uid(%d) call basesvr reduce coins error", uid))
        return false
    end
    if not succ then
        errlog(string_format("uid(%d) basesvr reduce coins succ == false error", uid))
        return false
    end

    --update_player_coins(uid, ret.curr)
    return ret
end

local function deduct_lost_coins(uid, coins, pay_fee_map)
    local robot = is_robot(uid)
    local ok, ret = reduce_coins(uid, coins, reason.LOSE_COIN, {is_robot = robot},get_extra_bill_info(uid))
    if not ok then
        return false
    end
    return ret.curr
end

local function give_winner_coins(uid, coins, pay_fee_map)
    local curr_coins = 0
    local robot = is_robot(uid)

    local ok, succ, ret = R().basesvr{ key = uid}:call(".msg_handler", "add_coins", 
        uid, coins + pay_fee_map[uid], reason.WIN_COIN, { is_robot = robot }, get_extra_bill_info(uid))
    if not ok then
        errlog(string_format("call basesvr uid(%d) coins(%d) reason(%s)", uid, coins, tostring_r(succ)))
        return false
    end

    if not succ then
        errlog(string_format("uid(%d) coins(%d)", uid, coins))
        return false
    end

    local ok,ret = reduce_coins(uid, pay_fee_map[uid], reason.PAY_FEE,get_extra_bill_info(uid))

    if not ret then
        errlog("reduce coins failed",tostring_r(ret) )
        return 
    end 


    R().basesvr{key=uid}:send('.msg_handler','sub_lose_coins', uid, coins)
    curr_coins = ret.curr

    -- R().basesvr({key=uid}):send('.msg_handler','add_player_fee_coins',uid,pay_fee_map[uid] or 0)
    -- billlog({op = "reducecoins",uid = uid,curr = curr_coins,value = pay_fee_map[uid],is_robot = robot,r = reason.PAY_FEE },get_extra_bill_info(uid))

    return curr_coins
end

local function get_player_curr_coins(uid)
    if player_info_list[uid] then
        return player_info_list[uid].coins
    else
        local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
        if not ok then
            errlog(uid,'get_player_curr_coins-->failed to get base_data')
            return 0
        end

        return base_data.coins
    end

    return 0
end

local function get_side_coins_result(side_player_coins_map,side)
    if not side_player_coins_map or not side then
        return 0,0
    end

    local roomdata = global_configs.roomdata[self_table_type]
    local fee_percent = (roomdata.cost or 5)/ 100 
    local total_side_win = 0
    local player_side_win = 0
    local player_win_list = {}
    for tmp_side,info in pairs(side_player_coins_map) do
        if tmp_side == side then
            for _,v in pairs(info) do
                local win_coins = v.result_coins
                total_side_win = total_side_win + win_coins
                if not is_robot(v.uid) then
                    player_side_win = player_side_win + win_coins
                     table_insert(player_win_list,{uid = v.uid,win_coins = win_coins})
                end
            end
        end
    end

    return total_side_win,player_side_win,player_win_list
end

local function write_card_record_log(bet_result_list,pay_fee_map,need_reduce_map,tile_list,side_player_coins_map,player_water)
    local winners = {}
    local losers = {}
    local have_player_bet = false 
    local player_win = 0
    local total_num = 0
    for uid, uid_bet_result in pairs(bet_result_list) do
        local player_info = player_info_list[uid]
        local left_coins = 0

        if player_info then
            left_coins = player_info.coins
        end

        local add_score =  uid_bet_result.result_coins
        if add_score > 0 then
            if not is_robot(uid) then
                 table_insert(winners, { 
                    uid = uid,  
                    left_score = left_coins,  
                    add_score = add_score,  
                    pay_fee = pay_fee_map[uid],  
                    is_robot = is_robot(uid),  
                    is_banker = is_banker(uid),
                })
            end
        else
            if not is_robot(uid) then
                table_insert(losers, { 
                    uid = uid,  
                    left_score = left_coins,  
                    add_score = add_score,  
                    pay_fee = pay_fee_map[uid],  
                    is_robot = is_robot(uid),
                    is_banker = is_banker(uid),
                })
            end
        end

        if not is_robot(uid) and uid > 0 then
            have_player_bet = true
            player_win = player_win + add_score
        end
        total_num = total_num + 1
    end

    local str_date = os.date("%Y%m%d%H%M%S")
    local all_bet_list = curr_brnn_instance:get_all_bet_list()
    local robot_bet_list = curr_brnn_instance:get_robot_side_bet_list()
    local side_list = {}
    for _,info in pairs(tile_list) do
        local side_info = {}
        side_info.side = info.side
        side_info.card_type = info.type
        side_info.cards = info.score
        side_info.bet_coins = all_bet_list[info.side] or 0
        side_info.player_bet_coins = side_info.bet_coins - (robot_bet_list[info.side] or 0)
        local total_side_win,player_side_win,player_win_list = get_side_coins_result(side_player_coins_map,info.side)
        side_info.total_side_win = total_side_win
        side_info.player_side_win = player_side_win
        if info.side == 5 then --庄家
            side_info.total_side_win  = is_robot(curr_banker_uid) and -player_win or player_win
        end
        side_info.player_win_list = player_win_list

        local player_bet_list = {}
        local side_bet_list = curr_brnn_instance:get_side_player_bet_list(info.side)
        for k,v in pairs(side_bet_list) do
            if not is_robot(v.uid) then
                table_insert(player_bet_list,{uid = v.uid,bet_coins = v.bet_coins})
            end
        end
        side_info.player_bet_list = player_bet_list
        side_info.banker_id = curr_banker_uid
        table_insert(side_list,side_info)
    end

    local exinfo = {
        system_result = system_result_type or 0,
        control_uid = gm_control_uid or 0,
        err_result = err_result or 0,
    }

    if have_player_bet then
        billlog({ op = "card_record",  
            table_gid = str_date .. "_" .. self_table_id,  
            game_type = self_game_type, 
            table_type = self_table_type,  
            begin_time = game_start_bet_time, 
            end_time = game_start_game_over_time,  
            curr_round = curr_round,  
            password = self_password, 
            winner_list = winners,  
            loser_list = losers, 
            system_win = -player_win,
            address = skynet.address(skynet.self()),
            side_list = side_list,
            exinfo = exinfo,
            total_num = total_num,
        })
    end

    local total_coins = 0
    for _,data in pairs(winners) do
        local uid = data.uid
        if need_reduce_map[uid] then
            local add_score = data.add_score + pay_fee_map[uid] or 0
            if not is_robot(uid) then
                total_coins = total_coins + math_abs(add_score)
                R().basesvr({key=uid}):send('.msg_handler','add_today_win_coins',uid,add_score)
                R().basesvr({key=uid}):send('.msg_handler','add_play_count',uid,1)

                local player_info = player_info_list[uid]
                local bet_coins = curr_brnn_instance:get_my_bet(uid) or 0
                player_info.all_win_lose = player_info.all_win_lose + data.add_score
                -- player_info.all_bet = player_info.all_bet + bet_coins
                player_info.all_produce = player_info.all_produce + add_score + bet_coins
                player_info.all_free = player_info.all_free + (pay_fee_map[uid] or 0)
                player_info.total_coins = player_info.total_coins + data.add_score
                dbglog("player_info.total_coins",player_info.total_coins,data.add_score)



                local uid = player_info.uid
                local bet_coins = bet_coins
                local produce = add_score + bet_coins
                local win_lose = data.add_score
                local free = (pay_fee_map[uid] or 0)            
                expand.sendSummary(self_table_type, uid, bet_coins, produce, win_lose, free)                 
                print("__1__brnn_sendSummary___", {uid, bet_coins, produce, win_lose, free})

                R().basesvr({key=uid}):send('.msg_handler','add_total_coins',uid,player_info.total_coins)
                player_info.total_coins = 0
            end          
        end
    end

    for _,data in pairs(losers) do
        local uid = data.uid
        if need_reduce_map[uid] then
            local add_score = data.add_score + pay_fee_map[uid] or 0
            if not is_robot(uid) then
                total_coins = total_coins + math_abs(add_score)
                R().basesvr({key=uid}):send('.msg_handler','add_play_count',uid,1)

                local player_info = player_info_list[uid]
                local bet_coins = curr_brnn_instance:get_my_bet(uid) or 0
                player_info.all_win_lose = player_info.all_win_lose + data.add_score
                player_info.all_produce = player_info.all_produce + add_score + bet_coins
                player_info.total_coins = player_info.total_coins + data.add_score
                dbglog("player_info.total_coins",player_info.total_coins,data.add_score)
                R().basesvr({key=uid}):send('.msg_handler','add_total_coins',uid,player_info.total_coins)
                player_info.total_coins = 0

                local uid = player_info.uid
                local bet_coins = bet_coins
                local produce = add_score + bet_coins
                local win_lose = data.add_score
                local free = (pay_fee_map[uid] or 0)
                expand.sendSummary(self_table_type, uid, bet_coins, produce, win_lose, free)     
                print("__2__brnn_sendSummary___", {uid, bet_coins, produce, win_lose, free})   
            end
     
            -- local curr_coins = get_player_curr_coins(uid)
            -- if not is_robot(uid) and curr_coins <= constant.POCHAN_COINS then --记录破产日志
            --     billlog({op = "bankrupt_register",uid = uid,game_type = self_game_type,
            --         table_type = self_table_type,
            --         ret = curr_coins,
            --     })
            -- end
        end
    end

    for uid,water_value in pairs(player_water) do 
        if not is_robot(uid) then
            R().basesvr({key=uid}):send('.msg_handler','add_person_water',uid,math_abs(water_value),is_robot(uid))
            billlog({ op   = "water_history",  
                table_gid  = str_date .. "_" .. self_table_id,
                table_type = self_table_type,
                uid        = uid,
                value      = math_abs(water_value),
                is_robot   = false,
            })
            dbglog("add_person_water")
            local player_info = player_info_list[uid]
            

        end
    end

    return total_coins
end
    
local function get_total_robot_fee(pay_fee_map)
    local roomdata = global_configs.roomdata[self_table_type]
    local total_robot_fee = 0
    if roomdata then  
        for uid, coins in pairs(pay_fee_map) do
            if is_robot(uid) then
                total_robot_fee = total_robot_fee + coins
            end
        end
    end

    return total_robot_fee
end

local function notify_caishenjiadao(uid,coins)
    print("=============notify_caishenjiadao",uid,coins)
    local curr_time = util.get_now_time()
    local countdown_time = global_configs.caishenjiadao.countdown_time or 10
    local end_time = curr_time + countdown_time + GAME_STATUS_GAMEOVER_WAIT_TIME --把动画时间加上
    caishen_coins_map[uid] = coins
    send_to_gateway(uid,uid_game_session_map[uid],'table.NTF_CAISHENJIADAO',
    {end_time = end_time,trigger_coins = coins,game_type = self_game_type})
    billlog({op = "caishenjiadao",type = "trigger",uid = uid,table_type = self_table_type,coins = coins})
end

--记录前五局输赢机器人的uid
local function robot_use_pic(bet_result_list)
    local win_list = record_pic_player.win_list
    local lose_list = record_pic_player.lose_list
    if not win_list then
        win_list = {}
        record_pic_player.win_list = win_list
    end
    if not lose_list then
        lose_list = {}
        record_pic_player.lose_list = lose_list
    end
    if #win_list >= 5 then
        table_remove(win_list,1)
    end
    if #lose_list >= 5 then
        table_remove(lose_list,1)
    end
    win_list[#win_list+1] = {}
    lose_list[#lose_list+1] = {}

    local uid_win_list = win_list[#win_list]
    local uid_lose_list = lose_list[#lose_list]

    local function is_times_enough(record_list,uid)
        for i = 1, 5 do
            if not record_list[i] then
                return false
            end
            if not record_list[i][uid] then
                return false
            end
        end
        return true
    end

    for uid, uid_bet_result in pairs(bet_result_list) do
        local result_coins = uid_bet_result.result_coins
        if is_robot(uid) then
            local player_info = player_info_list[uid]

            if result_coins >= 0 then
                uid_win_list[uid] = true
                if player_info and player_info.position then
                    if is_times_enough(win_list,uid) then
                        trigger_event('on_use_picture',uid,global_configs.robot_picture.brnn.win_five)
                    end 
                end
            else
                uid_lose_list[uid] = true
                if player_info and player_info.position then
                    if is_times_enough(lose_list,uid) then
                        trigger_event('on_use_picture',uid,global_configs.robot_picture.brnn.lose_five)
                    end 
                end
            end
        end
    end 
end

local function settle_game_coins(bet_result_list, pay_fee_map,bet_list)
    local settle_coins_functions = {}
    local settle_coins_result_robot = {}
    local system_win_lose = 0
    --对金币发生变化的机器人或玩家进行结算
    for uid, uid_bet_result in pairs(bet_result_list) do
        local deal_func = nil
        local result_coins = uid_bet_result.result_coins

        if system_do_banker(uid) then      
            goto continue
        end
        local player_info = player_info_list[uid]
        if is_robot(uid) then
            player_info.coins = player_info.coins + result_coins + (bet_list[uid] or 0)
            settle_coins_result_robot[uid] = player_info.coins
            if result_coins >= 0 then 
                --机器人赢钱时触发表情
                if player_info and player_info.position then
                    trigger_event('on_use_picture',uid,global_configs.robot_picture.brnn.robot_win)
                end
                -- R().basesvr{key=uid}:send('.msg_handler','sub_lose_coins', uid, result_coins)
                -- R().basesvr({key=uid}):send('.msg_handler','add_player_fee_coins',uid,pay_fee_map[uid] or 0)
                -- billlog({op = "reducecoins",uid = uid,curr = player_info.coins,value = pay_fee_map[uid],is_robot = is_robot(uid),r = reason.PAY_FEE },get_extra_bill_info(uid))
            else
                -- R().basesvr{key=uid}:send('.msg_handler','add_lose_coins', uid, math.abs(result_coins))
            end
        elseif result_coins >= 0 then
            system_win_lose = system_win_lose - result_coins
            deal_func = give_winner_coins
            if result_coins > 0 then
                R().basesvr({key=uid}):send('.msg_handler','add_wining_times',uid,self_game_type)
            end

            --检查是否触发财神驾到
            if player_info and not is_robot(uid) then
                local vip_level = player_info.vip_level
                local last_caishen_trigger_time = player_info.last_caishen_trigger_time
                --print("===========",uid,result_coins,self_table_type,vip_level or 0)
                if system_store.check_trigger_caishenjiadao(uid,result_coins,self_table_type,vip_level or 0) then
                    notify_caishenjiadao(uid,result_coins)
                end  
            end

            --添加玩家首冲进度
            -- R().activitysvr(1):send('.activity_mgr','act_add_first_charge_process',uid,result_coins + (pay_fee_map[uid] or 0))
        else
            system_win_lose = system_win_lose - result_coins
            deal_func = deduct_lost_coins
            R().basesvr({key=uid}):send('.msg_handler','add_losing_times',uid,self_game_type)
            --机器人输钱时触发表情
            if player_info and player_info.position then
                trigger_event('on_use_picture',uid,global_configs.robot_picture.brnn.robot_lose)
            end
        end        

        if deal_func then
            table_insert(settle_coins_functions, { 
                f = deal_func, 
                id = uid, 
                params = { uid, math.abs(result_coins + (bet_list[uid] or 0)), pay_fee_map }
             })
        end

        ::continue::
    end
    sendLoseWinToFriendServer(system_win_lose)
    --dbglog(string_format("settle_coins_functions(%s)", tostring_r(settle_coins_functions)))

    local ok, settle_coins_result = cocall(2, settle_coins_functions)
    dbglog(tostring_r(settle_coins_result))
    if not ok or not settle_coins_result then
        errlog(string_format("failed to cocall settle_coins_result(%s)", tostring_r(settle_coins_result)))
        return false
    end
    for uid,curr_coins in pairs(settle_coins_result) do
        if curr_coins and player_info_list[uid] then
            player_info_list[uid].coins = curr_coins
        end
    end

    for uid,curr_coins in pairs(settle_coins_result_robot) do
        settle_coins_result[uid] = curr_coins
    end

    --dbglog(string_format("settle_coins_result(%s)", tostring_r(settle_coins_result)))
    return true, settle_coins_result
end

local function notify_players_coins_change(settle_coins_result)
    local change_reason = constant.MONEY_CHANGED_REASON.BR_NN_AUDIT

    for uid, curr_coins in pairs(settle_coins_result) do
        if curr_coins then
            --这时候不确保玩家是否一定在桌子上，因此需要走大厅去通知金币变化
            if not system_do_banker(uid) and not is_robot(uid) then
                dbglog("notify_money_changed:",uid,curr_coins,change_reason)
                R().hallsvr{ key = uid }:send(".msg_handler", "toagent", uid, "notify_money_changed", { coins = curr_coins }, change_reason)
            end            
        else
            errlog(string_format("uid(%d) failed to cocall curr_coins(%s)", uid, tostring_r(curr_coins)))
        end
    end
end

local function settle_event_trigger(bet_result_list)
    for uid, uid_bet_result in pairs(bet_result_list) do
        if system_do_banker(uid) then
            goto continue
        end

        if is_robot(uid) then
            goto continue
        end
        --触发赢钱事件
        if uid_bet_result.result_coins > 0 then
             events.on_winning({ 
                uid = uid, 
                game_type = self_game_type, 
                table_type = self_table_type, 
                coins = uid_bet_result.result_coins,
             })

            -- R().exdbsvr(1):send(".event_mgr", "trigger", "on_winning", { 
            --     uid = uid, 
            --     game_type = self_game_type, 
            --     table_type = self_table_type, 
            --     coins = uid_bet_result.result_coins,
            --  })
        end

        events.on_play({ 
            uid = uid, 
            game_type = self_game_type, 
            table_type = self_table_type 
        })

        -- R().exdbsvr(1):send(".event_mgr", "trigger", "on_play", { 
        --     uid = uid, 
        --     game_type = self_game_type, 
        --     table_type = self_table_type 
        -- })

        ::continue::
    end
end

local function init_game_trend_list()
    
    for i = 1, brnn.MAX_SIDE_NUM - 1 do
        local side_list = {}
        game_trend_list[i] = side_list
        side_list.side = i
        side_list.result_list = {}
    end

    curr_game_trend_index = math_random(1,72)

    for i = 1,curr_game_trend_index do
        for side, side_list in pairs(game_trend_list) do
            local result = math_random(0,1)
            table_insert(side_list.result_list, 1, result)
        end   
    end

end

local function add_trend_to_list(sides_result_list)
    for side, side_list in pairs(game_trend_list) do
        local result = 0

        if sides_result_list[side].win then
            result = 1
        end

        table_insert(side_list.result_list, 1, result)
    end

    curr_game_trend_index = curr_game_trend_index + 1
end

local function remove_expired_trend()
    dbglog("brnn remove trend ")
    for side, side_list in pairs(game_trend_list) do
        side_list.result_list = {}
        --table_remove( side_list.result_list)
    end
    curr_game_trend_index = 0
end

local function update_game_trend(sides_result_list) 
    if curr_game_trend_index >= MAX_TREND_LIST_NUM then        
        remove_expired_trend()
    end

    add_trend_to_list(sides_result_list)
end

local function send_gameover_msg(tile_list, bet_result_list, settle_coins_result, system_banker_result)
    local rsp_bet_result_list = {}

    -- 所有人的GameResult
    for uid, uid_bet_result in pairs(bet_result_list) do
        if uid ~= constant.SYSTEM_DO_BANKER_UID then
            local player_info = player_info_list[uid]
--            dbglog(string_format("uid(%d)", uid))

            uid_bet_result.curr_coins = settle_coins_result[uid]
            uid_bet_result.position = player_info.position or 0
            table_insert(rsp_bet_result_list, uid_bet_result)
        end
        if not is_robot(uid) then
           dbglog("uid:",uid,"curr_coins",uid_bet_result.curr_coins) 
        end
    end

    if system_banker_result then
        system_banker_result.position = 0
        system_banker_result.curr_coins = -1
        table_insert(rsp_bet_result_list, system_banker_result)
    end
    dbglog(rsp_bet_result_list)
    local rsp_game_result = { 
        bet_result_list = rsp_bet_result_list,
        tile_list = tile_list,
     }

     local opt = check_stop_bet and constant.BRNN_OPT or ""
     notify_all("brnn.NTF_GAMEOVER", { 
        game_result = rsp_game_result, 
        left_time = GAME_STATUS_GAMEOVER_WAIT_TIME,
        trend_list = game_trend_list,
        opt = opt
     })

    g_game_result_info = rsp_game_result
end

local function update_robot_store(total_coins)
   local roomdata = global_configs.roomdata[self_table_type]
   if not roomdata or not roomdata.open_robot then
        return
   end

   local cnf = global_configs.robot_store[self_table_type]
   if not cnf then
        return
   end

   local fee_rate    = (cnf.fee_rate or 5) / 10000
   local award_rate  = (cnf.award_rate or 5) / 10000
   local fee_coins   = fee_rate * total_coins
   local award_coins = award_rate * total_coins
   
   R().exdbsvr(1):send('.system_coins_mgr','update_store',self_game_type,self_table_type,fee_coins,award_coins)
end

local function check_store_transfer()
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata then
        return
    end
 
    local cnf = global_configs.robot_store[self_table_type]
    if not cnf then
         return
    end

    local base_min  = cnf.base_min or 0
    local base_max  = cnf.base_max or 0
    local base_normal = cnf.base_normal or 0
    local data = {base_min = base_min,base_max = base_max,base_normal = base_normal,table_type = self_table_type}
    R().exdbsvr(1):send('.system_coins_mgr','check_store_transfer',self_game_type,data)
 end

local function update_control_store(add_coins)
    if add_coins > 0 then   
        local ok,coins = R().basesvr({key=control_player_uid}):call('.msg_handler','reduce_curr_control_data',control_player_uid,add_coins,self_game_type,true)
        local will_cost_coins = (ok and coins) and coins or 0
        local gm_add_coins = math_abs(system_money_cost) < math_abs(will_cost_coins) and math_abs(system_money_cost) or math_abs(will_cost_coins)
        gm_store_coins_add = gm_add_coins
    elseif add_coins < 0 then
        local ok,coins = R().basesvr({key=control_player_uid}):call('.msg_handler','add_curr_control_data',control_player_uid,math_abs(add_coins),self_game_type,true)
        local will_cost_coins = (ok and coins) and coins or 0
        local gm_add_coins = math_abs(system_money_cost) < math_abs(will_cost_coins) and math_abs(system_money_cost) or math_abs(will_cost_coins)
        gm_store_coins_add = gm_add_coins
    end
end

local function check_today_coins_water_goal(uid,data)
    local seven_reward = global_configs.seven_reward
    local goal_list = {}
    for k,v in pairs(seven_reward) do  
        table_insert(goal_list,(v.coins_low + v.coins_hight)/2)
        table_insert(goal_list,coins_hight)
    end

    local function get_section_and_high(value)
        local section,section_high
        for num,data in pairs(seven_reward) do
            if value >= data.coins_low then
                section = num
                section_high = data.coins_hight
            end 
        end

        return section,section_high
    end
    
    for _,value in pairs(goal_list) do
        if (data.pre_coins_water or 0) < value and (data.curr_coins_water or 0) >= value then
            local section,section_high = get_section_and_high(data.curr_coins_water or 0)
            local ntf = {
                today_coins   = data.curr_coins_water or 0,
                section_count = section,
                section_hight = section_high or 0,
                section_total_count = #seven_reward,
            }
            send_to_gateway(uid,uid_game_session_map[uid],'hall.NTF_SEVEN_REWARD_GOAL',ntf)
        end
    end
end

local function add_player_coins_water(bet_result_list,pay_fee_map)
    for uid, uid_bet_result in pairs(bet_result_list) do
        if not is_robot(uid) then
            local coins = math_abs(uid_bet_result.result_coins)
            if uid_bet_result.result_coins > 0 then
                coins = coins + pay_fee_map[uid]
            end
            local ok,ret = R().basesvr({key = uid}):call('.msg_handler','add_player_coins_water',uid,coins)
            print("add_player_coins_waterbbbbbbbbbb",ok,tostring_r(ret))
            -- if ok and ret then
            --     check_today_coins_water_goal(uid,ret)
            -- end
        end
    end
end

local function send_real_horse_message(bet_result_list)
    local roomdata = global_configs.roomdata[self_table_type] or {}
    local exinfo = cjson.encode({game_type = self_game_type})
    for uid,uid_bet_result in pairs(bet_result_list) do
        if not is_robot(uid) and uid_bet_result.result_coins > 0 then
            local player_info = player_info_list[uid]
            if player_info then
                R().mailsvr(1):send('.opration_message_worker','send_real_horse_message',constant.BROADCAST_IDS.BIDS_BRNN,
                {name = player_info.name,coin = uid_bet_result.result_coins,vip_level = player_info.vip_level})

                R().mailsvr(1):send('.opration_message_worker','send_real_horse_message',constant.BROADCAST_IDS.GUIDE_BROAD,
                {vip_level = player_info.vip_level,name = player_info.name,game_name = roomdata.name or '',coin =  uid_bet_result.result_coins,exinfo = exinfo})
            end
        end
    end
end

local function deal_special_pos(uid,pos)
    if not uid then return end
    --该特殊位置有人
    local sit_uid = seated_position_uid_map[pos]
    if sit_uid then
        if sit_uid == uid then   --玩家已经坐在该位置
            return false
        else      --该座位被别人占有，让他起来
            local player_info = player_info_list[sit_uid]
            if player_info and player_info.position then
                deal_stand_up(player_info, player_info.position)
            end
        end
    end
    --若玩家在坐下的情况下获得【富豪No.1】和【运气王】的头衔，则自动移动到相应位置
    local player_info = player_info_list[uid]
    if player_info and player_info.position then
        deal_stand_up(player_info, player_info.position)
    end

    --玩家入座
    deal_sit_down(uid,pos)
end

local function special_req_sit()
    local list = {}
    for _uid, player_info in pairs(player_info_list) do
        if not is_banker(_uid) then
            local win_rate = 0
            if player_info.play_count and player_info.play_count ~= 0 then
                win_rate = math_floor((player_info.win_count or 0) / player_info.play_count * 10000)
            end
            table_insert(list,{
                uid = _uid,
                win_count = player_info.win_count or 0,
                total_bet = player_info.total_bet or 0,
                play_count = player_info.play_count or 0,
                win_rate = win_rate,
            })
        end
    end

    if #list == 0 then
        return
    end 
    --富豪No.1
    table_sort(list,function(a,b)
        if a.total_bet ~= b.total_bet then
            return a.total_bet > b.total_bet
        else
            return a.win_count > b.win_count
        end
    end)
   -- print("==========special_req_sit====",tostring_r(list))
    local uid_rich_data = list[1]
    local rich_uid = uid_rich_data.uid

    deal_special_pos(rich_uid,brnn.RICH_SEAT_SIDE)
    
    --运气王(获胜局数/玩牌局数 → 下注金 → 获胜局数)
    table_sort(list,function(a,b)
        if a.win_rate ~= b.win_rate then
            return a.win_rate > b.win_rate
        elseif a.total_bet ~= b.total_bet then
            return a.total_bet > b.total_bet
        else
            return a.win_count > b.win_count 
        end
    end)

   -- print("==========special_req_sit====",player_avg_bet,tostring_r(list))
    local uid_luck_data = list[1]
    local luck_uid = uid_luck_data.uid
    --若两者玩家为同一个玩家时，【运气王】显示的玩家顺延至排名第二的玩家
    if luck_uid == seated_position_uid_map[brnn.RICH_SEAT_SIDE] then
        if #list < 2 then
            return
        end
        uid_luck_data = list[2]
        luck_uid = uid_luck_data.uid
    end
  
    --运气王的下注金额必须达到上一局玩家的下注金额均值
    if uid_luck_data.total_bet < player_avg_bet then
        for k, uid_info in pairs(list) do
            if uid_info.total_bet >= player_avg_bet and uid_info.uid ~= seated_position_uid_map[brnn.RICH_SEAT_SIDE] then
                luck_uid = uid_info.uid
                break
            end
        end
    end
   
    deal_special_pos(luck_uid,brnn.LUCK_SEAT_SIDE)
end

local function update_player_special_data()
    for uid,player_info in pairs(player_info_list) do
        player_info.win_count = 0
        player_info.total_bet = 0
        player_info.play_count = 0
    end
    for _,special_list in pairs(record_special_list) do
        for _uid,uid_special in pairs(special_list) do
            local player_info = player_info_list[_uid]
            if player_info then
                --更新一下玩家身上的数据
                player_info.win_count = (player_info.win_count or 0) + (uid_special.is_win or 0)
                player_info.total_bet = (player_info.total_bet or 0) + (uid_special.bet_coins or 0)
                player_info.play_count = (player_info.play_count or 0) + (uid_special.is_bet or 0)
            end
        end
    end
    special_req_sit()
end

--更新富豪No.1和运气王位置玩家
local function update_special_sit(bet_result_list)
    record_special_list[#record_special_list+1] = {} 
    if #record_special_list > 20 then
        table_remove(record_special_list,1)
    end

    local uid_rich_list = record_special_list[#record_special_list]
    local player_total_bet = 0 --本局玩家总下注
    local bet_player_num = 0   --本局下注的玩家

    for uid, uid_bet_result in pairs(bet_result_list) do
        uid_rich_list[uid] = {}
        local uid_specil = uid_rich_list[uid]
        local round_bet_coins = 0

        if curr_brnn_instance then
            round_bet_coins = curr_brnn_instance:get_uid_bet_total(uid)
        end 
        uid_specil.bet_coins = round_bet_coins
        if uid_bet_result.result_coins > 0 and not is_banker(uid) then--为庄家的话该局数据不用记录了  
            uid_specil.is_win = 1
        else
            uid_specil.is_win = 0
        end  
        uid_specil.is_bet = 0     --玩家是否有下注行为，用于统计桌子近20局玩家下注总局数
        --玩家的下注总金额
        if round_bet_coins > 0 then
            player_total_bet = player_total_bet + round_bet_coins
            bet_player_num = bet_player_num + 1
            uid_specil.is_bet = 1
        end
    end
    --记录一下该局玩家的下注金额均值
    player_avg_bet = 0
    if bet_player_num > 0 then
        player_avg_bet = math_floor(player_total_bet / bet_player_num)
    end
    --print("===========aaaaaaaaaa",player_avg_bet)
end

local function audit_game_result(game_result)
    local pay_fee_map = game_result.pay_fee_map
    local need_reduce_map = game_result.need_reduce_map
    local bet_result_list = game_result.bet_result_list
    local tile_list = game_result.tile_list
    local sides_result_list = game_result.sides_result_list
    local game_valid = game_result.game_valid
    local side_player_coins_map = game_result.side_player_coins_map
    local system_banker_result = nil
    local bet_list = game_result.bet_list
    local player_water = game_result.player_water

--    dbglog(string_format("game_result(%s)", tostring_r(game_result)))
    update_game_trend(sides_result_list)

    if not game_valid then
        dbglog("game_valid == false")
        send_gameover_msg(tile_list, {}, nil, nil)
        return true
    end
   
    local ok, settle_coins_result = settle_game_coins(bet_result_list, pay_fee_map,bet_list)
    if not ok then
        errlog("settle_game_coins error", tostring_r(pay_fee_map))
        return false
    end

    if bet_result_list[constant.SYSTEM_DO_BANKER_UID] then
        system_banker_result = bet_result_list[constant.SYSTEM_DO_BANKER_UID]
        bet_result_list[constant.SYSTEM_DO_BANKER_UID] = nil 
    end

    send_gameover_msg(tile_list, bet_result_list, settle_coins_result, system_banker_result)
    notify_players_coins_change(settle_coins_result)
    settle_event_trigger(bet_result_list)

    --添加玩家流水
    add_player_coins_water(bet_result_list,pay_fee_map)

    --根据机器人或系统输赢加减系统库存
    gm_store_coins_add = 0
    local award_result = curr_brnn_instance:get_system_result(robot_manager,self_table_type)
    print("award_result",award_result)
    if control_player_uid then     --更新个人控制库存
        local add_coins
        local uid_bet_result = bet_result_list[control_player_uid]
        if not uid_bet_result then
            add_coins = 0
        else
            add_coins = uid_bet_result.result_coins + pay_fee_map[control_player_uid]
        end
        dbglog("============222222222resul",add_coins,award_result)
        update_control_store(add_coins)
    end
    
    print("award_result=======333",award_result,gm_store_coins_add,award_result - gm_store_coins_add)
    award_result = award_result - gm_store_coins_add --减去gm库存部分
    local roomdata = global_configs.roomdata[self_table_type] or {}
    local robot_type = roomdata.robot_type or "brnn_normal"
    local is_update_reward_store = true
    if award_result >= 0 then
        R().exdbsvr(1):send('.system_coins_mgr','add_system_coins',self_game_type,self_table_type,award_result)
    else
        if reduce_award_store then --从奖励库存扣钱
            R().exdbsvr(1):send('.system_coins_mgr','reduce_award_coins',self_game_type,self_table_type,math_abs(award_result))
            is_update_reward_store = false
        else --从系统库存扣钱
            R().exdbsvr(1):send('.system_coins_mgr','sub_system_coins',self_game_type,self_table_type,math_abs(award_result))
        end
    end

    local total_coins = write_card_record_log(bet_result_list,pay_fee_map,need_reduce_map,tile_list,side_player_coins_map,player_water)
    --print("award_result=======444",award_resulttotal_coins,total_coins - math_abs(gm_store_coins_add))
    if is_update_reward_store then
        total_coins = total_coins - math_abs(gm_store_coins_add)
        update_robot_store(total_coins)
    end 
    check_store_transfer()

    send_real_horse_message(game_result.bet_result_list)
    robot_use_pic(bet_result_list)

    update_special_sit(bet_result_list)

    return true
end

local function unlock_all_players()
    for uid, _ in pairs(uid_game_session_map) do
        unlock_one_player(uid, self_table_gid)
    end
end

local function put_back_robots()
    for uid, _ in pairs(player_info_list) do
        if is_robot(uid) and robot_manager[uid] then
            robot_manager[uid]['on_exit'](robot_manager[uid])
            -- if enter_robot_map[uid] then
            --     enter_robot_map[uid] = nil 
            -- end
        end
    end
end


local function notify_matchsvr_table_stats(is_delete)
    local table_stats = {}
    if is_delete then
        table_stats.table_gid = self_table_gid
        table_stats.table_type = self_table_type 
        R().newmatchsvr(1):send(".table_mgr", "delete_table_stats", table_stats)
    else
--        dbglog("do update_table_stats")
        table_stats.table_type = self_table_type
        table_stats.left_num = table_def.game_player_num[self_game_type] - get_player_num()
        table_stats.table_gid = self_table_gid
        table_stats.table_pattern = self_table_pattern   
        --dbglog(tostring_r(table_stats))
        R().newmatchsvr(1):send(".table_mgr", "update_table_stats", table_stats)
    end
end

local function dissmiss_table()
    for uid, fd in pairs(uid_game_session_map) do
        if fd > 0 then
            realTimeWinLose(uid)
            send_to_gateway(uid,fd,'brnn.RSP_LEAVE',{result=error_code.RSP_SUCESS})
            watch_session(fd, uid, false)
        end

        skynet.send('.table_mgr','lua','leave',uid)
    end

    --玩家解除桌子锁定
    unlock_all_players()
    put_back_robots()
    billlog({ op = "close_table", status = curr_status, password = self_password })

    return true
end

local function close_table() 
    local ok, ret = xpcall(dissmiss_table, debug.traceback)
    if not ok then
        errlog(ret)
    end

    local uids = {}
    for uid,  _ in pairs(player_info_list) do
        table_insert(uids, uid)
    end

    notify_matchsvr_table_stats(true)  --更新桌子
    skynet.send(".table_mgr", "lua", "on_table_delete", self_table_id, uids)
    dbglog("now delete this table", self_table_id, uids)

    skynet.exit()
end

local function check_stop_table()
    local roomdata = global_configs.roomdata[self_table_type] or {}
    if stopping_server or roomdata.open_game == false then        
        billlog({op = "stop_table",status = curr_status,password = self_password})
        closing_server = true --直接关闭桌子
        close_table()
        return true
    end

    return false
end

local function check_close_table(curr_time)
    local closable = false
   --[[if closing_server or will_pattern_leave then
        closable = true
    end--]]
    if closing_server then
        closable = true
    end

    if not closable then
        return
    end
    close_table()
end

local function run_robots(new_robot_list)
    for _, robot_obj in pairs(new_robot_list) do
        skynet.fork(function() 
            robot_obj:update()     --出入上一局真实玩家下注总额
        end)
    end
end

local function robot_info_init_logic(robot_info, curr_time,robot_type)        
    --local position = get_next_can_sit_position()
    local robot_uid = robot_info.uid
    --dbglog(string_format("load robot uid(%d) position(%d)", robot_uid, position))

    local player_info = {
        uid = robot_uid,
        name = robot_info.name,
        coins = robot_info.coins,
        sex = robot_info.sex,
        icon = robot_info.icon,
        last_chat_time = 0,
        last_ping_time = curr_time,
        type    = robot_type,
        coins_type = robot_info.coins_type,
        icon_border = robot_info.icon_border,
        win_count = 0,
        total_bet = 0,
        play_count = 0,
        vip_level = robot_info.vip_level,
    }

    uid_game_session_map[robot_uid] = ROBOT_CLIENT_FD
    --seated_position_uid_map[position] = robot_uid
    player_info_list[robot_uid] = player_info
    add_to_noseat(robot_uid)
    --deal_sit_down(robot_uid, position)
    local betting_list = constant.BR_NN_AVAILABLE_BET_COINS_LIST

    local bet_list = global_configs.bet_list.brnn_bet_list
    if self_game_type == table_def.GAME_TYPE_TEN_BR_NN then
        bet_list = global_configs.bet_list.brnn_ten_bet_list
    end
    local available_betting_list = get_betting_list(bet_list,player_info.coins) or betting_list
    player_info.available_betting_list = available_betting_list

    local robot_obj = nn_robot.new(robot_uid, player_info, skynet.self(), ROBOT_CLIENT_FD,self_game_type, nil, self_table_type)
    robot_manager[robot_uid] = robot_obj
    robot_obj:canBet()
    --enter_robot_map[robot_uid] = true
    trigger_event("on_register", robot_uid)


    return robot_obj
end

local function load_robot()
    -- warlog("load_robot...")

    --判断是否开放机器人
    if not self_game_config.open_robot then
        dbglog("cant open robot")
        return false
    end
    local robot_type = self_game_config.robot_type or "brnn_normal"
    local robot_control  = global_configs.robot[robot_type]
    if not robot_control then
        errlog('load_robot fail because robotdata is nil')
        return
    end

    --if not next(player_info_list) then --如果没有玩家那么不去加载机器人
    --    return
    --end
    local robot_type_list = robot_control.robot_type_list
    --获取现有机器人人数
    local curr_robot_num_map = {}
    for uid,player_info in pairs(player_info_list) do
        if is_robot(uid) then
            local robot_type = player_info.coins_type
            if robot_type then
                curr_robot_num_map[robot_type] = (curr_robot_num_map[robot_type] or 0) + 1
            end
        end
    end

    local load_list = {}
    for type,data in pairs(robot_type_list) do
        local robot_num = utils.str_split(data.count_range,',')
        local coins_limit = utils.str_split(data.coins_range,',')
        local count = math_random(tonumber(robot_num[1]) or 0,tonumber(robot_num[2]) or 0)
        local curr_count = curr_robot_num_map[type] or 0
        if count > curr_count then
            load_list[type] = {count = count - curr_count,
                                coins_limit = {tonumber(coins_limit[1]) or 0,tonumber(coins_limit[2]) or 0}}
        end
    end
    
    -- 拉取机器人
--    print_r(load_list)
    if self_table_type == 200100 then 
        print("___total_bet_coins__", load_list)
    end
    local ok,succ,ret_map = R().robotmgr(1):call(".msg_handler","get_robot_type_list",load_list,robot_type)
    if not ok or not succ or not ret_map then
        errlog("load rebot is fail because succ is nil")
        return
    end

    if get_player_num() >= table_def.game_player_num[self_game_type] then
        R().robotmgr(1):send('.msg_handler','put_back_robots',ret_map)
        return
    end

    local curr_time = util.get_now_time()
    local load_ok_robot_list = {}
    if next(ret_map) then
        robot_enter_list = {}
    end
    for _, robot_info in pairs(ret_map) do
        dbglog("robot_uid:",robot_info.uid)
        --assert(not player_info_list[robot_info.uid],robot_info.uid)
        if not player_info_list[robot_info.uid] then
            local robot_obj = robot_info_init_logic(robot_info, curr_time,robot_type)
            table_insert(load_ok_robot_list, robot_obj)
            --机器人VIP入场广播
            table_insert(robot_enter_list, robot_info.uid)
        else
            errlog("player_info_list[robot_info.uid] not nil",player_info_list[robot_info.uid])
        end
    end

     --通知匹配服更新人数
    notify_matchsvr_table_stats()

    --fork robot协程
    run_robots(load_ok_robot_list)

    return true
end



local function time_to_load_robot(curr_time)
    warlog("time_to_load_robot...")
    warlog(curr_time, game_start_init_time, GAME_TIME_LOAD_ROBOT, game_start_wait_time)
           --1524907364 1524907363            5
           --1524907627 1524907623            5                    1524907623

    if curr_time > game_start_init_time + GAME_TIME_LOAD_ROBOT then 

        game_start_init_time = curr_time
        return true 
    end    

    return false
end

local function check_player_standup()
    local roomdata = global_configs.roomdata[self_table_type]
    local sit_coins_limit = roomdata.sit_coins_limit or 10000
    for position, uid in pairs(seated_position_uid_map) do
        if uid then 
            local play_info = player_info_list[uid]
            local msg = {position = position}
            local game_session = uid_game_session_map[uid]

            -- if is_banker(uid) then   --庄家uid站起
            --     handler.REQ_STANDUP(uid, msg, game_session)
            --     warlog(uid, tostring_r(msg), game_session)
            -- else
                local own_coins = play_info.coins
                if uid ~= seated_position_uid_map[brnn.RICH_SEAT_SID] and uid ~= seated_position_uid_map[brnn.LUCK_SEAT_SIDE] then
                    if ok and own_coins < sit_coins_limit then
                        handler.REQ_STANDUP(uid, msg, game_session)
                        dbglog("stand up player ===",uid)
                    end
                end
            -- end  
        end  
    end
end

local function get_lose_coins(uid)
    local ok,ret = R().basesvr{key=uid}:call('.msg_handler','get_lose_coins',uid)
    if not ok then
        errlog(uid,'failed to get_lose_coins ok is nil',ok)
        return
    end

    return ret
end

local function remove_from_bankers_queue(uid)
    for k, v in pairs(bankers_queue) do
        if v == uid then
            table_remove(bankers_queue, k)
            return
        end
    end
end

local function check_clear_banker_data(uid)
    if is_banker(uid) then
        set_need_change_banker_flag(true)
    end

    if in_bankers_queue(uid) then
        remove_from_bankers_queue(uid)
    end
end

local function player_leave(uid)
    assert(uid_game_session_map[uid])

    if uid_bet_map[uid] then
        --有押注过,暂时还不能解锁
        dbglog(uid,'this player is locked now...',uid_game_session_map[uid])
        uid_game_session_map[uid] = OFFLINE_CLIENT_FD
        return false
    end

    if is_banker(uid) then
        set_need_change_banker_flag(true)
        table_insert(pre_undo_banker, uid)
        uid_game_session_map[uid] = OFFLINE_CLIENT_FD
        return true
    end

    notify_all("brnn.NTF_LEAVE", { uid = uid })

    if not robot_manager[uid] then
        skynet.send('.table_mgr','lua','leave',uid)
        --R().hallsvr({key=uid}):send('.msg_handler', 'check_lucky_tigger',uid,self_game_type,init_coins) 注释掉鸿运系统
    end

    --清除庄家信息
    check_clear_banker_data(uid)

    clear_and_unlock_offline_player(uid)
    notify_matchsvr_table_stats()
    if not is_robot(uid) then
        R().friendsvr(1):send(".info_mgr", "update_info", uid, { curr_game_type = 0 })
    end
    --机器人归还
    if robot_manager[uid] then
        robot_manager[uid]['on_exit'](robot_manager[uid]) 
        robot_manager[uid] = nil
    end
    -- if enter_robot_map[uid] then
    --     enter_robot_map[uid] = nil 
    -- end
end

local function clear_offline_players()
    for uid, status in pairs(uid_game_session_map) do
        if status == OFFLINE_CLIENT_FD then
            local ok, ret = xpcall(player_leave, debug.traceback, uid)
            if not ok then
                errlog(uid, ret)
            end
        end
    end
end

local function check_bet_num()
    local ret5,ret4 = curr_brnn_instance:check_bet_num(player_info_list,player_not_bet_num)
    local roomdata = global_configs.roomdata[self_table_type] or {}
    for _,uid in pairs(ret5) do
        if in_bankers_queue(uid) then
            player_not_bet_num[uid] = 0
        else
            local robot = is_robot(uid)  
            if not robot then
                dbglog("RSP_KICK_LEAVE ",uid)
                send_to_gateway(uid,uid_game_session_map[uid],'table.NTF_LEAVE',{uid = uid ,reason=4,room_name = roomdata.name})
            end
            player_leave(uid)
        end
    end
    for _,uid in pairs(ret4) do
        if in_bankers_queue(uid) then
            player_not_bet_num[uid] = 0
        else
            local robot = is_robot(uid)  
            if not robot then
                send_to_gateway(uid,uid_game_session_map[uid],'table.NTF_TIPS',{type = 0,content = constant.BR_NO_BET_TIP})
            end
        end
    end
end

local function kick_coins_limit_robot()
--1.每种机器人，携带金币数高于上限或者低于下限时，退出房间。
--2.每局游戏，机器人都有退出房间的概率，初步设置为5%（数值可调），如果随机到多个机器人同时退出房间，则最多2个机器人执行退出房间的操作。

end

-- 轮班，老机器人退休后要换新的机器人
local function change_robot()
    local t = {}
    for uid, obj in pairs(robot_manager) do
        if obj.exit == true then
            table_insert(t, uid)    
        end
    end
    local num = 0;
    for k, uid in pairs(t) do
        robot_manager[uid] = nil
        num = num + 1
    end

    if num > 0 then
        load_robot(num)
    end
end

local function check_have_robot(player_list)
    for _,uid in pairs(player_list) do
        if is_robot(uid) then
            return true
        end
    end

    return false
end

local function get_personal_system_store_result(robot_type)
    local player_list = {}
    if not is_robot(curr_banker_uid) then
        table_insert(player_list,curr_banker_uid)
    end
    local betting_list = curr_brnn_instance:get_betting_uid_list()
    for _,uid in pairs(betting_list) do
        if not is_robot(uid) then
            table_insert(player_list,uid)
        end
    end

    local robot_store = global_configs.robot_store[self_table_type]
    local personal_control = global_configs.personal_control
    local gm_warn = (global_configs.gm_control or {}).warn_coins or 5000000
    local is_have_robot = check_have_robot(betting_list)
    is_curr_have_robot = is_have_robot
    local base_warn = robot_store.base_min or 0
   
    return system_store.get_personal_system_store_result(self_table_type,player_list,gm_warn,is_have_robot,base_warn)
end

local function check_robot_coins()
    local robot_type = self_game_config.robot_type or "brnn_normal"
    local robot_control = global_configs.robot
    for uid,player_info in pairs(player_info_list) do
        if is_robot(uid) then --如果是机器人，检查携带金币数高于该类型上限或者低于下限          
            local coins_type = player_info.coins_type
            if not coins_type then goto continue end
            local robot_config = robot_control[robot_type]
            local robot_type_info = robot_config.robot_type_list[coins_type] or {}
            --print_r(robot_type_info)
            local range = utils.str_split(robot_type_info.coins_range,',')
            if #range ~= 2 then
                return
            end

            if player_info.coins < tonumber(range[1]) or player_info.coins > tonumber(range[2]) then
                player_leave(uid)
            end
        end
        ::continue::
    end
end

local function check_undo_banker()
    local roomdata = global_configs.roomdata[self_table_type]
    local min_banker_coins = roomdata.min_banker_coins or 1500000

    for i=#bankers_queue,1,-1 do
        local uid = bankers_queue[i]
        local player_info = player_info_list[uid]
        if player_info and player_info.coins < min_banker_coins then
           table_remove(bankers_queue,i)
            if uid_game_session_map[uid] then
                send_to_gateway(uid,uid_game_session_map[uid],"brnn.RSP_UNDO_BANKER",{result = error_code.BE_TICKED_BANKER})
            end
        end
    end
end

local function get_lose_limit(store_result)
    local roomdata = global_configs.roomdata[self_table_type] or {}
    local robot_type = roomdata.robot_type or "brnn_normal"
    local robot_store = global_configs.robot_store
    local robot_config = robot_store[self_table_type]
    local lose_limit = robot_config.base_lose_limit or 100000
    if (store_result or 0) == constant.AWARD_STORE_LOSE then
        lose_limit = robot_config.award_lose_limit or 100000
    end

    return lose_limit
end

--根据库存策略调整牌型
local function adjust_cards()
    local system_result = 0
    local personal_uid
    control_player_uid = false
    reduce_award_store = false

    local roomdata = global_configs.roomdata[self_table_type]
    local robot_type = roomdata.robot_type or "brnn_normal"

    if not curr_brnn_instance:is_player_bet(robot_manager) and is_robot(curr_banker_uid) then
        return
    end

    system_result,personal_uid = get_personal_system_store_result(robot_type)
    system_result_type = system_result
    gm_control_uid = personal_uid

    dbglog("brnn_table_system_result:",system_result,"personal_uid:",personal_uid,"SYSTEM_NO_CONTROL:",constant.SYSTEM_NO_CONTROL)
    local lose_limit = get_lose_limit(system_result)
    if system_result == constant.PERSONAL_STORE_WIN and personal_uid then --控制个人赢
        control_player_uid = personal_uid
        err_result = curr_brnn_instance:control_player(robot_manager,self_table_type,lose_limit,personal_uid,true)
        if err_result ~= 0 then
            control_player_uid = false --个人控制失败标记
        end
    elseif system_result == constant.PERSONAL_STORE_LOSE and personal_uid then --控制个人输
        control_player_uid = personal_uid
        err_result = curr_brnn_instance:control_player(robot_manager,self_table_type,lose_limit,personal_uid,false)
        if err_result ~= 0 then
            control_player_uid = false --个人控制失败标记
        end
    elseif system_result == constant.SYSTEM_STORE_WIN then --控制系统赢
        err_result = curr_brnn_instance:control_result(robot_manager,self_table_type,lose_limit,true) 
    elseif system_result == constant.SYSTEM_STORE_LOSE then --控制系统输
        err_result = curr_brnn_instance:control_result(robot_manager,self_table_type,lose_limit,false) 
    elseif system_result == constant.AWARD_STORE_LOSE then
        reduce_award_store = true                    --玩家从奖金库存拿钱
        err_result = curr_brnn_instance:control_result(robot_manager,self_table_type,lose_limit,false) 
    elseif system_result == constant.SYSTEM_NO_CONTROL then --不控制情况下
        dbglog("brnn_table_system_result",system_result)
        curr_brnn_instance:suiji_result(robot_manager,self_table_type,lose_limit) 
    else
        dbglog("====system_result error====",system_result)
    end
end

local function set_last_banker_info(uid)
    if system_do_banker(uid) then
        local name = rand_robot_name() 
        local info = {uid = constant.BR_NN_BANKER_INFO.uid,name = name,icon = constant.BR_NN_BANKER_INFO.icon}
        last_banker_info = info
    elseif player_info_list[uid] then
        last_banker_info = get_rsp_player_info(player_info_list[uid])
    else
        dbglog("get player_info fail",uid)
    end
end

local function add_robot_banker(count)
    print("==========add_robot_banker",count)
    local can_banker_list = {}
    for uid,obj in pairs(robot_manager) do
        local player_info = player_info_list[uid]
        if player_info and (player_info.coins_type or 0) == 6 then --优先选上庄机器人
           if not is_banker(uid) and not in_bankers_queue(uid) and coins_meet_banker_condition(uid) then
                table_insert(can_banker_list,uid)
            end
        end
    end

    if #can_banker_list < count then --如果人数还不够 找其他机器人
        for uid,obj in pairs(robot_manager) do
            local player_info = player_info_list[uid]
            if player_info and (player_info.coins_type or 0) ~= 6 then --选其他机器人
               if not is_banker(uid) and not in_bankers_queue(uid) and coins_meet_banker_condition(uid) then
                    table_insert(can_banker_list,uid)
                end
            end
        end
    end

    if #can_banker_list < count then
        count = #can_banker_list
    end

    print("sssssssssssssssssssssssss",count,tostring_r(can_banker_list))
    for i=1,count do
        local id = math_random(1,#can_banker_list)
        print("index",id)
        local uid = table_remove(can_banker_list,id)
        print(uid)
        local round = get_banker_round(player_info_list[uid].coins)
        robot_manager[uid]['on_do_banker'](robot_manager[uid],round)
    end
end

local function check_robot_do_banker()
    print("===============================check_robot_do_banker")
    local player_num = get_player_num_without_robot()
    local roomdata = global_configs.roomdata[self_table_type] or {}
    local robot_type = roomdata.robot_type or "brnn_normal"
    local brnn_banker_control = global_configs.robot_banker_control[robot_type]
    local obj = brnn_banker_control.banker_rate[1]
    for id,banker_obj in ipairs(brnn_banker_control.banker_rate) do
        if banker_obj.min <= player_num and banker_obj.max >= player_num then
            obj = banker_obj
        end
    end

    print("banker_obj is ",tostring_r(obj),player_num)
    local rate = obj.rate
    if math_random(1,100) > rate then
        return
    end
    banker_number = obj.number
    local banker_info = get_banker_queue_info()
    local curr_banker_count = #banker_info.banker_list
    if banker_number > curr_banker_count then
        add_robot_banker(banker_number - curr_banker_count)
    end

    return
end

local function record_player_start_coins()
    for uid,player_info in pairs(player_info_list) do
        start_coins_map[uid] = player_info.coins
    end
end

local function set_curr_special_uid()
    if not seated_position_uid_map[brnn.RICH_SEAT_SIDE] or not seated_position_uid_map[brnn.LUCK_SEAT_SIDE] then 
        special_req_sit()
    end
end

--获取每种类型的机器人可下注总额度
local function get_robot_total_bet_coins()
    local roomdata = global_configs.roomdata[self_table_type] or {}
    local robot_type = roomdata.robot_type or "brnn_normal"
    local robot_control  = global_configs.robot[robot_type]
    if not robot_control or not robot_control.robot_type_list then
        errlog("robot_control robot_type:",robot_type)
        return
    end
    
    local robot_bet_coins = {}
    for coins_type, v in pairs(robot_control.robot_type_list) do
        local last_bet_rate = v.system_last_bet_rate / 100  --上局下注选用比例
        local bet_min = v.system_bet_min +  (last_player_betting_coins or 0) * last_bet_rate   --机器人下注下限
        local bet_float = utils.str_split(v['bet_area_float'],'-')
        local float = math_random(tonumber(bet_float[1]),tonumber(bet_float[2]))

        --可下注额度
        local total_bet = math_floor(bet_min * (float / 100))
        robot_bet_coins[coins_type] = total_bet
    end
    return robot_bet_coins
end

--指定类型的机器人能下的总注
local function get_robot_total_coins()
    local robot_total_coins_type = {}
    for uid,v in pairs(player_info_list) do
        if is_robot(uid) then --剔除上庄机器人的钱
            local robot = robot_manager[uid]
            local coins = v.coins
            if robot and not robot:getCanBet() then 
                coins = 0
            end            
            if robot_total_coins_type[v.coins_type] then
                robot_total_coins_type[v.coins_type] = robot_total_coins_type[v.coins_type] + (coins or 0)
            else
                robot_total_coins_type[v.coins_type] = (coins or 0)
            end
        end
    end
    return robot_total_coins_type
end

-- local function check_robot_ntf_enter(curr_time)

--     local play_effect = false
--     local player_info = player_info_list[uid]
--     local enter_word = ""
--     local vip_level_conf = utils.getDataBykv(global_configs.vip,"level",player_info.vip_level or 0)
--     if vip_level_conf and vip_level_conf.privilege[game_def.VIP_PRIVILEGE_TYPE_SIX] then
--         play_effect = true
--         enter_word = vip_level_conf.enter_word or ""
--     end
--     notify_all("brnn.NTF_PLAYER_ENTER", {play_effect = play_effect,enter_word = enter_word,player = get_rsp_player_info(player_info)})
-- end

function update(curr_time)
    --dbglog("---------========================", curr_status, TABLE_STATUS_STRING[curr_status])
    -- dbglog("++++++++++++++++curr_time:",curr_time)
    if curr_status == TABLE_STATUS.TABLE_STATUS_WAIT then
        if curr_time - game_start_wait_time >= GAME_STATUS_WAIT_TIME then
            curr_status = TABLE_STATUS.TABLE_STATUS_CHECK_START
            load_robot()
            check_robot_do_banker()
        end
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_CHECK_START then
        if meet_start_condition() then
            check_player_standup()
            local robot_total_coins_type = get_robot_total_coins()
            local robot_bet_coins = get_robot_total_bet_coins()
            trigger_event("on_start",curr_brnn_instance,nil,robot_bet_coins,robot_total_coins_type)
            game_start_pad_time = curr_time            
            curr_round = curr_round + 1

            if is_robot(curr_banker_uid) and curr_banker_uid ~= 0 and robot_manager[curr_banker_uid] then
                print("banker is robot",curr_banker_uid)
                robot_manager[curr_banker_uid]['on_become_banker'](robot_manager[curr_banker_uid])
            end

            local player_info_list = get_seated_list() --get_rsp_player_info_list()
            local banker_info_list = get_banker_queue_info()

            local banker_change_status = BANKER_CHANGE_NO
            --print_r(last_banker_info)
            if curr_banker_uid ~= last_banker_info.uid then
                banker_change_status = BANKER_CHANGE_YES

            end
            game_start_banker_time = curr_time  
            curr_status = TABLE_STATUS.TABLE_STATUS_CHANGE_BANKER
            notify_all("brnn.NTF_START", { player_list = player_info_list, banker_info = banker_info_list,
                        banker_change_status = banker_change_status,last_banker_info = last_banker_info,})
            --更新入座富豪No.1和运气王
            update_player_special_data() --庄家是不能坐在特殊位置的，待客户端让庄家站起后再更新特殊位置吧
            --记录游戏开始玩家金币数
            record_player_start_coins()

            -- if curr_status ~= TABLE_STATUS_CHANGE_BANKER then
            --     curr_status = TABLE_STATUS_REAL_TIME_PAD_BEGIN
            --     game_start_pad_time = curr_time
            --     notify_all('brnn.NTF_START_PAD',{
            --         left_time = GAME_REAL_TIME_PAD
            --     })
            -- end
            set_last_banker_info(curr_banker_uid)

            -- check_stop_bet = false
        end
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_CHANGE_BANKER then
        if curr_time - game_start_banker_time >= GAME_TIME_CHANGE_BANKER then
            curr_status = TABLE_STATUS.TABLE_STATUS_REAL_TIME_PAD_BEGIN
            game_start_pad_time = curr_time
            notify_all('brnn.NTF_START_PAD',{
                left_time = GAME_REAL_TIME_PAD
            })
        end
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_REAL_TIME_PAD_BEGIN then
        if curr_time - game_start_pad_time >= GAME_REAL_TIME_PAD then
            curr_brnn_instance:start_bet()
            curr_status = TABLE_STATUS.TABLE_STATUS_BET
            game_start_bet_time = curr_time 
            local total_bet_coins,left_bet_coins = curr_brnn_instance:get_bet_info(self_game_type)
            notify_all("brnn.NTF_BET_START",{left_time = GAME_STATUS_BET_TIME,
                        curr_total_bet_coins=total_bet_coins,curr_left_bet_coins=left_bet_coins})
            trigger_event("on_time_to_bet", GAME_TIME_BET, record_last_player_bet)
        end      
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_BET then
        if curr_time - game_start_bet_time >= GAME_STATUS_BET_TIME then --or check_stop_bet then
            game_start_game_over_time = curr_time
            curr_status = TABLE_STATUS.TABLE_STATUS_GAMEOVER
            curr_brnn_instance:stop_bet()
        end
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_GAMEOVER then 
        if curr_time - game_start_game_over_time >= GAME_REAL_TIME_PAD_END then
            local roomdata = global_configs.roomdata[self_table_type]
            local fee_percent = (roomdata.cost or 5) / 100

            adjust_cards()
            curr_brnn_instance:judge_result(fee_percent,self_table_type)

            local ok, ret = xpcall(audit_game_result, debug.traceback, curr_brnn_instance:get_game_result())
            if not ok then
                errlog(ret)
            end
                    
            uid_bet_map = {}
            record_last_player_bet = curr_brnn_instance:get_player_bet_total(robot_manager)
            clear_offline_players()
            game_start_game_over_wait_time = curr_time
            curr_status = TABLE_STATUS.TABLE_STATUS_GAMEOVER_WAIT
        end
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_GAMEOVER_WAIT then
        if curr_time - game_start_game_over_wait_time >= GAME_STATUS_GAMEOVER_WAIT_TIME then
            check_stop_table()
            check_bet_num()
            check_undo_banker()
            if #pre_undo_banker > 0 then
                set_need_change_banker_flag(true)
                set_banker_by_turn()
                pre_undo_banker = {}
            end
            load_config()
            trigger_event("on_game_over")
            self_game_config = global_configs.roomdata[self_table_type]
            --check_robot_coins()
            curr_status = TABLE_STATUS.TABLE_STATUS_RESTART
        end
    elseif curr_status == TABLE_STATUS.TABLE_STATUS_RESTART then
        --kick_coins_limit_robot()
        -- --更新入座富豪No.1和运气王
        -- update_player_special_data()
        curr_brnn_instance = nil
        g_game_result_info = nil        
        game_start_wait_time = curr_time    
        notify_all("brnn.NTF_WAIT_START", { left_time = GAME_STATUS_WAIT_TIME + GAME_TIME_CHANGE_BANKER })
        
        --trigger_event("on_game_over")
        --change_robot()

        --can_take_compensation()
        
        -- 通知破产
        --[[
        for uid, _ in pairs(uid_game_session_map) do
            notify_take_compensation(uid)
        end
        --]]
        
        curr_status = TABLE_STATUS.TABLE_STATUS_WAIT
        -- load_config()
       
    else
        errlog(string_format("unknown status(%d)", curr_status))
    end
    --当前没有运气王或富豪时，随机指定一个
    set_curr_special_uid()
    check_robot_ntf_enter(curr_time)
    check_close_table(curr_time) 
end

local function game_update()
    curr_status = TABLE_STATUS.TABLE_STATUS_WAIT
    --先加载一次机器人
    load_robot()

    while true do
        local curr_time = util.get_now_time()
        local ok, ret = xpcall(update, debug.traceback, curr_time)
        if not ok then 
            errlog(ret)
        end
        skynet.sleep(50)
    end
end

function internal.get_player_num()
    return get_player_num()
end

function internal.sync_table_stats()
    local left_num = table_def.game_player_num[self_game_type] - get_player_num()
    if left_num < 0 
        then left_num = 0 
    end

    local table_stats = {}
    table_stats.table_gid = self_table_gid
    table_stats.left_num = left_num
    table_stats.table_pattern = self_table_pattern
    return self_table_type, table_stats
end

function internal.get_game_type()
    return self_game_type, self_table_type
end

local function get_non_robot_players_num()
    local player_num = 0

    for _, uid in pairs(seated_position_uid_map) do
        if not system_do_banker(uid) then
            player_num = player_num + 1
        end        
    end

    return player_num    
end

--在线玩家概况数据
function internal.get_summary_online()
    local res = {}
    for uid, player in pairs(player_info_list) do 
        if not is_robot(uid) then 
            table_insert(res, {
                uid = uid, 
                all_bet = player.all_bet, --总投注
                all_win_lose = player.all_win_lose, --输赢
                all_free = player.all_free, --台费
                all_produce = player.all_produce, --总产出
            })
        end
    end
    return res
end

function internal.get_user_playing_info()
    local playing_info = {}
    playing_info.game_type = self_game_type
    playing_info.table_type = self_table_type
    playing_info.total = get_non_robot_players_num()

    return playing_info
end

--[[
local function collect_betting_action(uid, curr_coins, side, bet_coins)
    local key = uid << 8 | side
    local player_bet = g_bet_batch_list[key]

    if not player_bet then
        player_bet = {}
        g_bet_batch_list[key] = player_bet
    end

    local bet_coins_list = player_bet.bet_coins_list
    if not bet_coins_list then
        bet_coins_list = {}
        player_bet.bet_coins_list = bet_coins_list
    end

    table_insert(bet_coins_list, bet_coins)
    player_bet.curr_coins = curr_coins
end


function check_and_sync_betting_action()
    if not next(g_bet_batch_list) then
        return
    end

    local bet_info_list = {}

    for key, player_bet in pairs(g_bet_batch_list) do
        local uid = key >> 8
        local side = key & 0xFF
        local curr_coins = 0
        local position = 0        

        local player_info = player_info_list[uid]
        if player_info then
            position = player_info.position
        end

        table_insert(bet_info_list, { 
            uid = uid, 
            bet_coins_list = player_bet.bet_coins_list, 
            curr_coins = player_bet.curr_coins, 
            side = side, 
            position = position,
         })

        g_bet_batch_list[key] = nil
    end
    
    
    
    local ntf = { 
        bet_info_list = bet_info_list, 
     }


    notify_all("brnn.NTF_BET", ntf)
    return true
end


local function routine_sync_bet_action()
    while true do
        local ok, ret = xpcall(check_and_sync_betting_action, debug.traceback)
        if not ok then
            errlog(ret)
        end
        skynet.sleep(30)
    end
end
--]]

local function add_to_bankers_queue(uid)
    table_insert(bankers_queue, uid)
end


function handler.REQ_DO_BANKER(uid, msg, game_session)
    dbglog(string_format("uid(%d) game_session(%d)", uid, game_session))

    if not is_game_session_correct(uid, game_session) then
        return false
    end

    if is_banker(uid) then   
        errlog(string_format("uid(%d) DOING_BANKER_ERROR", uid))     
        send_to_gateway(uid, game_session, "brnn.RSP_DO_BANKER", { result = error_code.DOING_BANKER_ERROR })
        return true
    end

    if in_bankers_queue(uid) then   
        errlog(string_format("uid(%d) HAD_APPLY_BANKER_ERROR", uid))     
        send_to_gateway(uid, game_session, "brnn.RSP_DO_BANKER", { result = error_code.HAD_APPLY_BANKER_ERROR, banker_info=get_banker_queue_info() })
        return true
    end

    --如果是机器人请求上庄，判断上庄人数是否达到配置的值
    if is_robot(uid) then
        local banker_info = get_banker_queue_info()
        local curr_banker_count = #banker_info.banker_list
        if curr_banker_count >= banker_number then
            dbglog("banker is enough",uid)
            return
        end
    end

    --如果玩家上庄，随机上庄列表中的一个机器人50%概率下庄
    if not is_robot(uid) then
        local robot_list = {}
        for _,_uid in pairs(bankers_queue) do
            if is_robot(_uid) and robot_manager[_uid] then
                table_insert(robot_list,_uid)
            end
        end
        if #robot_list > 0 then
            local robot_uid = robot_list[math_random(1,#robot_list)]
            if robot_manager[robot_uid] then
                robot_manager[robot_uid]['on_player_do_banker'](robot_manager[robot_uid])
            end
        end
        dbglog("REQ_DO_BANKER ",curr_banker_uid,"is_robot",is_robot(curr_banker_uid),system_do_banker(curr_banker_uid))
        --通知庄家1-3局内下庄
        if is_robot(curr_banker_uid) and not system_do_banker(curr_banker_uid) then
            if robot_manager[curr_banker_uid] then
                 dbglog("REQ_DO_BANKER on_player_do_banker")
                robot_manager[curr_banker_uid]['on_player_do_banker'](robot_manager[curr_banker_uid])
            end
        end
    end

    if not coins_meet_banker_condition(uid) then
        errlog(string_format("uid(%d) NO_MONEY_FOR_DO_BANKER_ERROR", uid))     
        send_to_gateway(uid, game_session, "brnn.RSP_DO_BANKER", { result = error_code.NO_MONEY_FOR_DO_BANKER_ERROR, banker_info=get_banker_queue_info() })
        return true
    end

    if system_do_banker(curr_banker_uid) then
        set_need_change_banker_flag(true)
    end

    add_to_bankers_queue(uid)

    -- local player_info = player_info_list[uid]
    -- if player_info.position and seated_position_uid_map[player_info.position] == uid then
    --     seated_position_uid_map[player_info.position] = false
    --     player_info.position = nil
    -- end
    send_to_gateway(uid, game_session, "brnn.RSP_DO_BANKER", { result = error_code.RSP_SUCESS, banker_info=get_banker_queue_info() })
--[[
    notify_all("brnn.NTF_BANKER_ACTION", { 
        action = BANKER_ACTION.DO_BANKER,
        uid = uid,
        banker_info = get_banker_queue_info(),
     })
--]]
    return true
end

function handler.REQ_UNDO_BANKER(uid, msg, game_session)
    if not is_game_session_correct(uid, game_session) then
        return false
    end

    local in_table = function(t, elem)
        for k, v in pairs(t) do
            if v == elem then
                return true
            end
        end
        return false
    end


    if in_table(pre_undo_banker, uid) then
        --已经申请过下庄了

        --send_to_gateway(uid, game_session, "brnn.RSP_UNDO_BANKER", { result = error_code.PALYING_CANT_UNDO_BANKER_ERROR,banker_info=get_banker_queue_info() })
        send_to_gateway(uid, game_session, "brnn.RSP_UNDO_BANKER", { result = error_code.ACCEPT_UNDO_BANKER_EFFECTIVE_LATER, banker_info=get_banker_queue_info() })

        return true
    end

    if not is_game_status_correct(uid, TABLE_STATUS.TABLE_STATUS_WAIT) and is_banker(uid) then
        table_insert(pre_undo_banker, uid)

        --比赛中，稍后自动下庄

        --send_to_gateway(uid, game_session, "brnn.RSP_UNDO_BANKER", { result = error_code.PALYING_CANT_UNDO_BANKER_ERROR,banker_info=get_banker_queue_info() })
        send_to_gateway(uid, game_session, "brnn.RSP_UNDO_BANKER", { result = error_code.ACCEPT_UNDO_BANKER_EFFECTIVE_LATER, banker_info=get_banker_queue_info() })
        return true
    end

    if is_banker(uid) then
        set_need_change_banker_flag(true)
        set_banker_by_turn()
    else
        remove_from_bankers_queue(uid)
    end

    send_to_gateway(uid, game_session, "brnn.RSP_UNDO_BANKER", { result = error_code.RSP_SUCESS, banker_info=get_banker_queue_info() })

    return true
end

local function bet_in_previous_second()
    local curr_time = util.get_now_time()

    --if curr_time - game_start_bet_time >= GAME_STATUS_BET_TIME - 1 then
    if curr_time - game_start_bet_time > GAME_STATUS_BET_TIME  then
        errlog(string_format("curr_time(%d) - game_start_bet_time(%d) >= GAME_STATUS_BET_TIME(%d) - 1", 
            curr_time, game_start_bet_time, GAME_STATUS_BET_TIME))
        return true
    end

    return false
end

local function get_bet_index(available_bet_list,bet_coins)
    for index,coins in pairs(available_bet_list) do
        if coins == bet_coins then
            return index
        end
    end
end

local function get_bet_min()
    local bet_list = global_configs.bet_list.brnn_bet_list
    if self_game_type == table_def.GAME_TYPE_TEN_BR_NN then
        bet_list = global_configs.bet_list.brnn_ten_bet_list
    end

    local bet_min = bet_list[1].bet_list[1] or 100
    for _,v in pairs(bet_list) do
        if v.bet_list[1] < bet_min then
            bet_min = v.bet_list[1]
        end
    end

    return bet_min
end

function handler.REQ_BET(uid, msg, game_session)
    local side = msg.side
    local bet_coins = msg.bet_coins
    local bet_type = msg.bet_type

    if not is_game_status_correct(uid, TABLE_STATUS.TABLE_STATUS_BET) then
        --屏蔽机器人报错日志
        if not is_robot(uid) then
           errlog("error_code.BET_DEADLINE_ERROR ",curr_status)
        end
        send_to_gateway(uid, game_session, "brnn.RSP_BET", { result = error_code.BET_DEADLINE_ERROR })
        return true
    end

    local player_info = assert(player_info_list[uid])
    start_coins_map[uid] = start_coins_map[uid] or player_info.coins
    local start_coins = start_coins_map[uid] 
    local roomdata = global_configs.roomdata[self_table_type]
    local brnn_min_bet = roomdata.min_bet or 0

    if self_game_type == table_def.GAME_TYPE_BR_NN and start_coins < brnn_min_bet then
        if not is_robot(uid) then       
            errlog("error_code.BRNN_BET_MIN_COINS_LIMIT ")
        end
        local res = utils.getErrResult(error_code.BRNN_BET_MIN_COINS_LIMIT, brnn_min_bet)
        send_to_gateway(uid, game_session, "brnn.RSP_BET", res)
        return true
    end

    if self_game_type == table_def.GAME_TYPE_TEN_BR_NN and start_coins < brnn_min_bet then
        if not is_robot(uid) then
            errlog("error_code.BRNN_BET_MIN_COINS_LIMIT ")
        end
        local res = utils.getErrResult(error_code.BRNN_TEN_BET_MIN_COINS_LIMIT, brnn_min_bet)
        send_to_gateway(uid, game_session, "brnn.RSP_BET", res)
        return true
    end

    local ok,succ = curr_brnn_instance:can_bet(uid,side,bet_coins,player_info,is_robot(uid),bet_type,self_table_type)
    -- print("__7___total_bet_coins___", ok, succ) 
    if not ok then
        send_to_gateway(uid, game_session, "brnn.RSP_BET", { result = succ })
        return true
    end

    -- local ok, ret = curr_brnn_instance:bet(uid,side,bet_coins, player_info,is_robot(uid),bet_type,self_table_type)
    -- if not ok then
    --     errlog(string_format("uid(%d) failed to betting bet_coins(%d) reason(%d)", uid, bet_coins, ret))
    --     send_to_gateway(uid, game_session, "brnn.RSP_BET", { result = ret })
    --     return true
    -- end
    local robot = is_robot(uid)
    local ok,succ,ret
    --去扣钱
    if robot then
        ok,ret = curr_brnn_instance:bet(uid,side,bet_coins,player_info,is_robot(uid),bet_type,self_table_type)
        if not ok then
           -- errlog(uid,'failed to betting coins',bet_coins)
            send_to_gateway(uid,game_session,'brnn.RSP_BET',{result = ret})
            return
        end
        player_info.coins = player_info.coins - bet_coins
    else
        ok,succ,ret = R().basesvr{key=uid}:call('.msg_handler',
            'reduce_coins',uid,bet_coins,reason.BET_COIN,{is_robot=robot},get_extra_bill_info(uid))
        if not ok or not succ then
            errlog(uid,'failed to reduce coins',ok,succ,bet_coins)
            send_to_gateway(uid,game_session,'brnn.RSP_BET',
                {result = error_code.GOLD_IS_NOT_ENOUGH})
            return
        end

        --异步完后，必须是可押注状态
        if curr_status ~= TABLE_STATUS.TABLE_STATUS_BET then
            errlog(uid,'failed to check status',bet_coins,curr_status)
            --如果此时不可押注，则返回钱
            R().basesvr{key=uid}:call('.msg_handler','add_coins',uid,bet_coins,reason.BET_COIN_BACK,
                {is_robot=robot},get_extra_bill_info(uid))
            send_to_gateway(uid,game_session,'brnn.RSP_BET',{result = -113})
            return
        end

        local curr_coins = ret.curr
        ok,ret = curr_brnn_instance:bet(uid,side,bet_coins,player_info,is_robot(uid),bet_type,self_table_type)
        if not ok then
            errlog(uid,'failed to betting coins',bet_coins,"ret:",ret)
            --如果此时不可押注，则返回钱
            R().basesvr{key=uid}:call('.msg_handler','add_coins',uid,bet_coins,reason.BET_COIN_BACK,
                {is_robot=robot},get_extra_bill_info(uid))
            send_to_gateway(uid,game_session,'brnn.RSP_BET',{result = ret})
            return
        end
        player_info.coins = curr_coins
        -- player_info.all_win_lose = player_info.all_win_lose - bet_coins
        -- player_info.total_coins = player_info.total_coins - bet_coins
        -- dbglog("player_info.total_coins",player_info.total_coins,bet_coins)

        player_info.all_bet = player_info.all_bet + bet_coins
        R().basesvr{key=uid}:send('.msg_handler','add_lose_coins',uid,bet_coins)
    end
    
    uid_bet_map[uid] = true

    --collect_betting_action(uid, ret.curr_coins, side, bet_coins)

    send_to_gateway(uid, game_session, "brnn.RSP_BET", { 
        result = error_code.RSP_SUCESS
     })
    
    local bet_min = get_bet_min()

    --获取剩余可下注金币
    local total_bet_coins,left_bet_coins = curr_brnn_instance:get_bet_info(self_game_type)
    --dbglog("==========left_bet_coins",left_bet_coins,"sss",bet_min)
    -- if left_bet_coins and left_bet_coins < bet_min then
    --     check_stop_bet = true
    -- end
    
    local bet_index = get_bet_index(player_info.available_betting_list,bet_coins)
    local bet_info_list = {}
    table_insert(bet_info_list, { 
        uid = uid, 
        bet_coins_list = {bet_coins}, 
        curr_coins = player_info.coins, --player_info.coins, 
        side = side, 
        position = player_info.position,
        curr_total_bet_coins = total_bet_coins,
        curr_left_bet_coins = left_bet_coins,
        bet_index = bet_index,
     })
     
     local ntf = { 
        bet_info_list = bet_info_list, 
     }


    notify_all("brnn.NTF_BET", ntf)

    return true
end

function handler.REQ_SITDOWN(uid, msg, game_session)
    local position = msg.position

--    dbglog(string_format("uid(%d) game_session(%d) position(%d)", uid, game_session, position))

    if not is_game_session_correct(uid, game_session) then
        return false
    end

    --外部不能请求入座特殊位置(包括机器人)
    if position == brnn.RICH_SEAT_SIDE or pos == brnn.LUCK_SEAT_SIDE then
        send_to_gateway(uid, game_session, "brnn.RSP_SITDOWN", { result = error_code.SEAT_SPECIAL_SIDE })
        return true
    end

    local ok, ret, sitdown_coin = deal_sit_down(uid, position)
    if not ok then
        local res = utils.getErrResult(ret, sitdown_coin)
        send_to_gateway(uid, game_session, "brnn.RSP_SITDOWN", res)
        return true
    end

    send_to_gateway(uid, game_session, "brnn.RSP_SITDOWN", { result = error_code.RSP_SUCESS })
    
    return true
end

local function get_next_can_sit_position()
    local can_position = 0

    for position, uid in pairs(seated_position_uid_map) do
        if not uid then
            can_position = position
            break
        end
    end

    return can_position
end

function handler.REQ_STANDUP(uid, msg, game_session)
    local position = msg.position
    dbglog("uid==game_session==position===",uid,game_session,position)

    if not is_game_session_correct(uid, game_session) then
        return false
    end

    local player_info = player_info_list[uid]

    local ok, ret = deal_stand_up(player_info, position)
    if not ok then
        --send_to_gateway(uid, game_session, "brnn.RSP_STANDUP", { result = ret })
        return true
    end

    --add_to_noseat(uid)
    --send_to_gateway(uid, game_session, "brnn.RSP_STANDUP", { result = error_code.RSP_SUCESS })
    return true
end

function handler.REQ_CHAT(uid, msg)
    local player_info = assert(player_info_list[uid])
    local curr_time = util.get_now_time()

    if player_info.last_chat_time and curr_time - player_info.last_chat_time < 1 then
        send_to_gateway(uid, uid_game_session_map[uid], "table.RSP_CHAT", { result = error_code.REQ_CHAT_TOO_FAST })
        return true
    end

    player_info.last_chat_time = curr_time
    send_to_gateway(uid, uid_game_session_map[uid], "table.RSP_CHAT", { result = error_code.RSP_SUCESS })

    local ntf = { 
        uid = uid, 
        type = msg.type, 
        picture_id = msg.picture_id, 
        content = msg.content, 
        voice = msg.voice, 
        content_id = msg.content_id, 
        name = player_info.name, 
        icon = player_info.icon, 
        sex = player_info.sex, 
     }

    notify_all("table.NTF_CHAT", ntf)

    return true
end

local function had_betted(uid)
    if uid_bet_map[uid] then
        dbglog(string_format("uid(%d) had bet", uid))        
        return true
    end

    return false
end

function handler.REQ_LEAVE(uid, msg, game_session)

    if not is_game_session_correct(uid, game_session) then
        return false
    end

    local player_info = player_info_list[uid]
    if not player_info then
        return false
    end

    -- if had_betted(uid) then
    --     --uid_game_session_map[uid] = OFFLINE_CLIENT_FD
    --     send_to_gateway(uid, game_session, "brnn.RSP_LEAVE", { result = error_code.HAD_BET_CANT_LEAVE_ERROR })
    --     return true
    -- end

    if game_not_over() and is_banker(uid) then
        dbglog(string_format("uid(%d) doing banker", uid))
        --uid_game_session_map[uid] = OFFLINE_CLIENT_FD
        --set_need_change_banker_flag(true)
        --set_banker_by_turn()
        send_to_gateway(uid, game_session, "brnn.RSP_LEAVE", { result = error_code.DOING_BANKER_PLS_LEAVE_LATER })
        return true
    end

    -- local init_coins = player_info.init_coins or 0
    -- local robot = is_robot(uid)
    player_leave(uid)

    send_to_gateway(uid, game_session, "brnn.RSP_LEAVE", { result = error_code.RSP_SUCESS })
    -- watch_session(game_session, uid, false)
    -- skynet.send(".table_mgr", "lua", "leave", uid)

    
    -- if not robot then
    --     R().hallsvr({key=uid}):send('.msg_handler', 'check_lucky_tigger',uid,self_game_type,init_coins)
    -- end

    return true
end

function handler.REQ_PLAYER_LIST(uid, msg, game_session)
    if not is_game_session_correct(uid, game_session) then
        return false
    end

    local luck_uid = seated_position_uid_map[brnn.LUCK_SEAT_SIDE]
    local rich_uid = seated_position_uid_map[brnn.RICH_SEAT_SIDE]

    local player_list = get_rsp_player_info_list(luck_uid,rich_uid)
    --下注金额→获胜局数→玩牌局数
    table_sort(player_list,function(a,b)
        if a.total_bet ~= b.total_bet then
            return a.total_bet > b.total_bet
        elseif a.win_count ~= b.win_count then
            return a.win_count > b.win_count
        else
            return a.play_count < b.play_count
        end
    end)

    --运气王置顶显示
    local luck_info = player_info_list[luck_uid]
    local rich_info = player_info_list[rich_uid]
    if luck_info then
        table_insert(player_list,1,get_rsp_player_info(luck_info))
    end
    if rich_info then
        if #player_list == 0 then
            table_insert(player_list,get_rsp_player_info(rich_info))
        else
            table_insert(player_list,2,get_rsp_player_info(rich_info))
        end
    end

    send_to_gateway(uid, game_session, "brnn.RSP_PLAYER_LIST", { 
        result = error_code.RSP_SUCESS,
        players = player_list
    })
    return true
end

function handler.REQ_TREND_LIST(uid, msg, game_session)
    if not is_game_session_correct(uid, game_session) then
        return false
    end

    send_to_gateway(uid, game_session, "brnn.RSP_TREND_LIST", { 
        result = error_code.RSP_SUCESS,
        trend_list = game_trend_list,
     })

    return true
end

function handler.REQ_BANKER_LIST(uid, msg, game_session)
    dbglog(string_format("uid(%d) game_session(%d)", uid, game_session))

    if not is_game_session_correct(uid, game_session) then
        return false
    end

    send_to_gateway(uid, game_session, "brnn.RSP_BANKER_LIST", { 
        result = error_code.RSP_SUCESS,
        banker_info = get_banker_queue_info(),
     })

    return true
end

function handler.REQ_COINS_CHANGE(uid, msg, game_session)
    dbglog(string_format("uid(%d)", uid))

    if not is_game_session_correct(uid, game_session) then
        return false
    end

    local own_coins = get_own_coins(uid)

    local player_info = player_info_list[uid]
    player_info.coins = own_coins

    send_to_gateway(uid, game_session, "brnn.RSP_COINS_CHANGE", { result = error_code.RSP_SUCESS })
    return true
end    

function handler.REQ_USE_MAGIC_PICTURE(uid, msg, game_session)
    local dst_id = msg.dst_id
    local picture_id = msg.picture_id 

    dbglog(string_format("uid(%d) dst_id(%d) picture_id(%d)", uid, dst_id, picture_id))

    if not is_game_session_correct(uid, game_session) then
        return false
    end

    local src_player_info = player_info_list[uid]
    if not src_player_info then
        errlog(string_format("uid(%d) player info is null", uid))
        return false
    end

    -- if not src_player_info.position then
    --     send_to_gateway(uid, game_session, "table.RSP_USE_MAGIC_PICTURE",{result = error_code.USE_ITEM_NEED_POSTION})
    --     return false
    -- end

    local dst_player_info = player_info_list[dst_id]
    if not dst_player_info then
        errlog(string_format("uid(%d) dst_id(%d) dst player info is null", uid, dst_id))
        send_to_gateway(uid, game_session, "table.RSP_USE_MAGIC_PICTURE", { 
            result = error_code.TABLE_USE_MAGIC_PICTURE_DST_MUST_SITDOWN })
        return true
    end


    if not dst_player_info.position and not is_banker(dst_player_info.uid) then
        errlog(string_format("uid(%d) dst_id(%d) dst player no seat", uid, dst_id))
        send_to_gateway(uid, game_session, "table.RSP_USE_MAGIC_PICTURE", { 
            result = error_code.TABLE_USE_MAGIC_PICTURE_DST_MUST_SITDOWN })
        return true
    end
   
--[[
    local ok, ret = reduce_coins(uid, constant.USE_MAGIC_PICTURE_COIN, reason.USE_MAGIC_PICTRUE, get_extra_bill_info(uid))
    if not ok then
        send_to_gateway(uid, game_session, "table.RSP_USE_MAGIC_PICTURE", { result = error_code.GOLD_IS_NOT_ENOUGH })
        return true
    end

    src_player_info.coins = ret.curr
--]]

    local player_info = player_info_list[uid]

    send_to_gateway(uid, game_session, "table.RSP_USE_MAGIC_PICTURE", {})

    notify_all("table.NTF_USE_MAGIC_PICTURE", { 
        src_id = uid, 
        dst_id = dst_id, 
        picture_id = picture_id, 
        coins = player_info.coins, 
     })

    --utils.notify_money_changed(uid, { coins = ret.curr }, game_session)
    return true
end

--换游戏
-- function handler.REQ_GAME_CHANGE(uid,msg,game_session)
--     local roomdata_list = global_configs.roomdata or {}
--     local roomdata = roomdata_list[msg.table_type]
--     if not roomdata then
--         errlog(self_table_type,"check_game_change_table but roomdata is nil")
--         return false
--     end

--     local player_info = player_info_list[uid]
--     if not player_info then
--         dbglog("REQ_GAME_CHANGE error player_info is nil", uid)
--         send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.PERMISSION_DENIDE})
--         return false
--     end

--     if player_info.coins < (roomdata.min or 0) then
--         send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.GOLD_IS_NOT_ENOUGH})
--         return false
--     end

--     if (roomdata.max or 0) ~= 0 and player_info.coin > (roomdata.max or 0) then
--         send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.GOLD_OUT_OF_MAX})
--         return false
--     end

--     if had_betted(uid) then
--         send_to_gateway(uid, game_session, "table.RSP_GAME_CHANGE", { result = error_code.HAD_BET_CANT_LEAVE_ERROR })
--         return true
--     end

--     if game_not_over() and is_banker(uid) then
--         dbglog(string_format("uid(%d) doing banker", uid))
--         send_to_gateway(uid, game_session, "table.RSP_GAME_CHANGE", { result = error_code.DOING_BANKER_PLS_LEAVE_LATER })
--         return true
--     end

--     player_leave(uid) --玩家离开

--     local user_data = {
--         uid = uid,
--         table_type = msg.table_type,
--         begin_time = util.get_now_time(),
--         name = player_info.name,
--         coins = player_info.coins,
--         sex = player_info.sex,
--         icon = player_info.icon,
--         --old_table_gid = self_table_gid,
--         --ip_limit = false,
--         --login_ip = player_info.login_ip,
--     }   

--     --请求匹配服进行匹配了
--     local ok = R().newmatchsvr(1):call(".table_mgr", "match_player",user_data)
--     if not ok then
--         errlog(string_format("uid(%d) call newmatchsvr table_mgr match_player error",uid))
--         send_to_gateway(uid, game_session, "table.RSP_GAME_CHANGE", { result = error_code.RSP_FAIL })
--         return true
--     end
--     send_to_gateway(uid, game_session, "table.RSP_GAME_CHANGE", { result = error_code.RSP_SUCESS })

--     return true
-- end

local function update_player_coins(uid, coins)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.coins = coins
    else
        errlog(string_format("uid(%d) coins(%d) player info not exist", uid, coins))
    end
end

local function get_my_bet_total(uid)
    local total = 0
    local bet_list = curr_brnn_instance:get_my_bet_list(uid)
    if bet_list then
        for side,coins in pairs(bet_list) do
            total = total + coins
        end
    end
    return total
end

local function check_have_enough_coins(uid,coins)
    local player_info = player_info_list[uid]
    if not player_info or player_info.coins < coins then
        return false
    end

    if curr_status == TABLE_STATUS.TABLE_STATUS_BET or curr_status == TABLE_STATUS.TABLE_STATUS_GAMEOVER then
        local total_coins =  get_my_bet_total(uid)
        if self_game_type == table_def.GAME_TYPE_BR_NN and player_info.coins - total_coins * 3 < coins then
                return false
        elseif self_game_type == table_def.GAME_TYPE_TEN_BR_NN and player_info.coins - total_coins * 10 < coins then
                return false
        end
    end

    return true
end

local function caishen_coins(uid, coins, award_coins, ...)
    local robot = is_robot(uid)
    local ok, succ, ret = R().basesvr({ key = uid }):call(".msg_handler", "caishen_coins", uid, coins, award_coins, {is_robot=robot},get_extra_bill_info(uid))
    if not ok then
        errlog(string_format("uid(%d) call basesvr caishen_coins coins error", uid))
        return false
    end
    if not succ then
        errlog(string_format("uid(%d) basesvr caishen_coins coins succ == false error", uid))
        return false
    end

    --update_player_coins(uid, ret.curr)
    return ret
end

local function pay_caishen_coins(uid,coins)
    local caishenjiadao_store = global_configs.caishenjiadao_store
    local fee_rate = caishenjiadao_store.fee_rate
    local sysback_coins = math_floor((coins *fee_rate) / 10000)
    local base_coins = coins - sysback_coins
    local curr_coins
    local ret_coins = system_store.check_caishen_store_result(self_table_type,uid,coins)
    local player_info = player_info_list[uid]
    player_info.all_bet = player_info.all_bet + coins
    local produce = 0
    local win_lose = 0
    if ret_coins then
        print("add coins",ret_coins)
        curr_coins = caishen_coins(uid,coins,ret_coins)
        if not curr_coins then
            errlog("reduce coins failed",ret )
            return error_code.NOT_ENOUGH_COINS
        end
        sendLoseWinToFriendServer(coins - ret_coins)
        --改变财神库存
        R().exdbsvr(1):send('.caishen_mgr','push_data_pool',self_table_type,uid,base_coins,sysback_coins)
        R().exdbsvr(1):send('.caishen_mgr','sub_caishen_base',self_table_type,uid,ret_coins)
        player_info.all_win_lose = player_info.all_win_lose - coins + ret_coins
        player_info.all_produce = player_info.all_produce + ret_coins
        produce = ret_coins       
        win_lose =  - coins + ret_coins           
    else
        local ok,ret = reduce_coins(uid, coins, reason.OPEN_CAISHEN)
        if not ok then
            errlog("reduce coins failed",ret )
            return error_code.NOT_ENOUGH_COINS
        end
        sendLoseWinToFriendServer(coins)
        --改变财神库存
        R().exdbsvr(1):send('.caishen_mgr','push_data_pool',self_table_type,uid,base_coins,sysback_coins)
        curr_coins = ret.curr
        player_info.all_win_lose = player_info.all_win_lose - coins        
        win_lose =  - coins  
        ret_coins = 0       
    end
    local uid = uid
    local bet_coins = coins
    local produce = produce
    local win_lose = win_lose
    local free = 0
    expand.sendSummary(self_table_type, uid, bet_coins, produce, win_lose, free)


    utils.notify_money_changed(uid,{coins = curr_coins})
    notify_all("table.NTF_MONEY_CHANGED", { chged_list = { { uid = uid, coins = curr_coins } } })
    
    update_player_coins(uid, curr_coins)
    caishen_coins_map[uid] = nil
    return error_code.RSP_SUCESS,ret_coins    
end

function handler.REQ_OPEN_CAISHEN(uid,msg)
    local coins = msg.coins
    --[[if not caishen_coins_map[uid] or caishen_coins_map[uid] ~= coins then
        errlog("put coins error",uid,caishen_coins_map[uid])
        return
    end]]
    if not caishen_coins_map[uid] or coins ~= caishen_coins_map[uid] then
        errlog("your param is error",uid,coins)
        send_to_gateway(uid,uid_game_session_map[uid],'table.RSP_OPEN_CAISHEN',{result = error_code.INPUT_ERROR})
        return false
    end

    if not check_have_enough_coins(uid,coins) then
        errlog("you have not enough coins",uid)
        send_to_gateway(uid,uid_game_session_map[uid],'table.RSP_OPEN_CAISHEN',{result = error_code.NOT_ENOUGH_COINS})
        return false
    end
    local res,ret_coins = pay_caishen_coins(uid,coins)
    if res == error_code.RSP_SUCESS then
        send_to_gateway(uid,uid_game_session_map[uid],'table.RSP_OPEN_CAISHEN',{result = res,award_coins = ret_coins})
    else
        send_to_gateway(uid,uid_game_session_map[uid],'table.RSP_OPEN_CAISHEN',{result = res})
    end
end

function handler.REQ_PERSONAL_INFO(uid,msg,game_session)
    local player_info = player_info_list[msg.uid]
    local ret = {}
    if player_info then
        local personal_info = {
            uid = player_info.uid,
            name = player_info.name,
            sex = player_info.sex,
            icon = player_info.icon,
            coins = player_info.coins,
            is_self = false,
            vip_level = player_info.vip_level or 0,
            icon_border = player_info.icon_border,
        }
        ret.personal_info = personal_info
        ret.is_set_down = player_info.position and true or false
        send_to_gateway(uid,game_session,'table.RSP_PERSONAL_INFO',ret)
    else
        send_to_gateway(uid,game_session,'table.RSP_PERSONAL_INFO',{result = error_code.NO_SUCH_PLAYER})
    end
    
    return true
end

function game_not_over()
    --if curr_status == TABLE_STATUS_BET or curr_status == TABLE_STATUS_GAMEOVER then
    --    return true
    --end

    if curr_status ~= TABLE_STATUS.TABLE_STATUS_WAIT then
        return true
    end

    return false
end

function internal.disconnect(uid, game_session)
    dbglog(string_format("uid(%d) game_session(%d) disconnect", uid, game_session))

    if not is_game_session_correct(uid, game_session) then
        return false
    end

    -- if had_betted(uid) then
    --     uid_game_session_map[uid] = OFFLINE_CLIENT_FD
    --     return true
    -- end

    player_leave(uid)
    return true
end

function internal.stop_server()
    stopping_server = true
end

function internal.close_server()
    closing_server = true
end

function internal.tmp_close_table()
    local player_num = get_player_num_without_robot()
    if player_num <= 0 then
        closing_server = true
    end
end

function internal.enter(uid, game_session, msg)
    local ok, result = deal_enter(uid, game_session, msg)
    if not ok then
        send_to_gateway(uid, game_session, "table.RSP_ENTER", { result = result })
        return false
    end

    --dbglog(string_format("=================>result(%s)", tostring_r(result)))

    send_to_gateway(uid, game_session, "table.RSP_ENTER", result)

    watch_session(game_session, uid, true)
    if not is_robot(uid) then
        R().friendsvr(1):send(".info_mgr", "update_info", uid, { curr_game_type = self_game_type,curr_table_type=self_table_type })
    end
    local play_effect = false
    local player_info = player_info_list[uid]
    local enter_word = ""
    local vip_level_conf = utils.getDataBykv(global_configs.vip,"level",player_info.vip_level or 0)
    if vip_level_conf and vip_level_conf.privilege[game_def.VIP_PRIVILEGE_TYPE_SIX] then
        play_effect = true
        enter_word = vip_level_conf.enter_word or ""
    end
    notify_all("brnn.NTF_PLAYER_ENTER", {play_effect = play_effect,enter_word = enter_word,player = get_rsp_player_info(player_info)})
    if player_info.position then
        trigger_event('on_use_picture',uid,global_configs.robot_picture.robot_enter,true)
    end
    return true
end

function internal.touch(key)
end


local function get_card_type_times_map()
    local card_type_times_map = {}
    local special_card_type = constant.NN_NAME_DEFAULT_SPECIAL_CARD_TYPE_MAP
    --local tabletType = game_def.get_game_type(self_table_type)
    if self_game_type == table_def.GAME_TYPE_BR_NN then -- or tabletType == table_def.GAME_TYPE_TEN_BR_NN then
        for _, card_type in pairs(special_card_type) do
            if card_type == special_card_type.FOUR_BOMBS then
                card_type_times_map[card_type] = 5
            elseif card_type == special_card_type.FIVE_COLOR_CATTLES then
                card_type_times_map[card_type] = 5
            elseif card_type == special_card_type.FIVE_CALVES then
                card_type_times_map[card_type] = 5
            end
        end

        for card_type = 0, 10 do
            if card_type <= 2 then
                card_type_times_map[card_type] = 1
            elseif card_type >= 3 and card_type <= 5 then
                card_type_times_map[card_type] = 2
            elseif card_type >= 6 and card_type <= 8 then
                card_type_times_map[card_type] = 3
            elseif card_type == 9 then
                card_type_times_map[card_type] = 4
            elseif card_type == 10 then
                card_type_times_map[card_type] = 5
            end
        end
    elseif self_game_type == table_def.GAME_TYPE_TEN_BR_NN then
        for _, card_type in pairs(special_card_type) do
            card_type_times_map[card_type] = 10
        end

        for card_type = 0, 10 do
            if card_type == 0 then
                card_type_times_map[card_type] = 1
            else
                card_type_times_map[card_type] = card_type
            end
        end
    end
    dbglog(card_type_times_map)
    return card_type_times_map
end

function get_sort_special_card_type()
    local sorted_special_card_type = {}

    for _, card_type in pairs(constant.NN_NAME_DEFAULT_SPECIAL_CARD_TYPE_MAP) do
        table_insert(sorted_special_card_type, card_type)
    end

    table_sort(sorted_special_card_type)
    return sorted_special_card_type
end

function internal.start(conf)   
    self_table_id = conf.table_id
    self_table_type = conf.table_type
    self_table_gid = conf.table_gid
    self_game_type = conf.game_type
    self_table_pattern = conf.table_conf.table_pattern   --记录了桌子的模式以及机器人的数量robot_num,table_pattern
    curr_round = 0

    init_position()

    self_game_config = global_configs.roomdata[self_table_type]
    dbglog("self_game_config.open_robot",self_game_config.open_robot)
    curr_status = TABLE_STATUS.TABLE_STATUS_WAIT
    game_start_init_time = util.get_now_time()
    game_start_wait_time = util.get_now_time()
    card_type_times_map = get_card_type_times_map()
    sorted_special_card_type = get_sort_special_card_type()
    g_bet_batch_list = {}
    init_game_trend_list()
    --init_available_bet_list()
    set_table_status_string()

    dbglog(string_format("conf(%s) \nid<%d>, type(%d), gid(%d)", tostring_r(conf), self_table_id, self_table_type, self_table_gid))
    skynet.fork(game_update)
    --skynet.fork(routine_sync_bet_action)

    --load_robot()
    return true
end

function internal.exit()
    skynet.exit()
end

function internal.update_coins_on_table(uid, amount,safe_box)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.coins = player_info.coins + amount
        start_coins_map[uid] = player_info.coins
        local chged_list = {}
        table_insert(chged_list,{uid=uid,coins=player_info.coins})
        if player_info.position then
            notify_all('table.NTF_MONEY_CHANGED',{chged_list=chged_list})
        else
            send_to_gateway(uid,uid_game_session_map[uid],'table.NTF_MONEY_CHANGED',{chged_list = chged_list})
        end
        if safe_box then
            player_info.safe_box = safe_box
        end
    end
    return true
end

function internal.newmatch_register_all(player_data_list)
    local result = {}
    local failed_list = {}
    local success_list = {}

    dbglog("=====================1111111111self_table_pattern",self_table_pattern,self_table_gid)
    for i, player_data in pairs(player_data_list) do
        local uid = player_data.uid
        uid_game_session_map[uid] = REGISTER_CLIENT_FD
        table_insert(success_list, uid)
    end

    result.failed_list = failed_list
    result.success_list = success_list
    local table_stats = {}
    table_stats.table_type = self_table_type
    table_stats.left_num = table_def.game_player_num[self_game_type] - get_player_num()
    table_stats.table_gid = self_table_gid
    table_stats.game_type = self_game_type
    table_stats.table_pattern = self_table_pattern
    result.table_stats = table_stats

    return result
end

function internal.get_trend_info()
    local roomdata = global_configs.roomdata[self_table_type]
    local result = {}
    if roomdata.person_limit then
        result.min = roomdata.person_limit[1] or 0
        result.max = roomdata.person_limit[2] or 0
    end
    result.winner_side_list = {}
    result.curr_status,result.left_time,result.status_time = get_client_status_and_left_time()
    result.name = roomdata.name
    result.table_type = self_table_type
    result.game_type = game_def.get_game_type(self_table_type)
    result.eject_rate = roomdata.eject_rate
    result.eject_time = roomdata.eject_time
--    print_r(game_trend_list)
    for side, side_list in pairs(game_trend_list) do
        for i = 1, #side_list.result_list do
            local v = side_list.result_list[#side_list.result_list - i + 1]
            result.winner_side_list[i] = result.winner_side_list[i] or 0
            result.winner_side_list[i] = result.winner_side_list[i] + 10^(side - 1)*v
        end
    end
  --  print_r(result)
    return result 
end
--=================================table protocols=================
local function update_player_heartbeat(uid)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.last_ping_time = util.get_now_time()
    end
end

local function get_msg_module_name(msgid)
    local m = msgdef.id_to_name[msgid]

    if not m then 
        return false, false
    end

    return m[1], m[2] --[1]->module, [2]->name
end

function dispatch_client_message(game_session, uid, msg, size)
    local _, msgid, pbmsg, pbsize = proxypack.unpack_client_message(msg, size)
    local module, name = get_msg_module_name(msgid)

    if not module or not name then
        dbglog(string_format("msgid(%d) module(%s) name(%s) invalid msgid", msgid, module, name))
        return false
    end

    local pbname = module .. "." .. name
    local req_msg = pb.decode(pbname, pbmsg, pbsize)

    dbglog(string_format("address(%s) uid(%s) pbname(%s) content(%s)", 
        skynet.address(skynet.self()), tostring_r(uid), pbname, tostring_r(req_msg)))

    local f = handler[name]
    if not f then
        errlog(string_format("pbname(%s) unknown action", pbname))
        return false
    end

    local ret = f(uid, req_msg, game_session)
    if not ret then
        errlog(string_format("failed to handle requrest(%s.%s)", module, name))
        return false
    end

    update_player_heartbeat(uid)
    return true
end

local function dispatch(_, _, game_session, uid, data)
    local msg, size = proxypack.pack_raw(data)
    local ok, errmsg = xpcall(dispatch_client_message, debug.traceback, game_session, uid, msg, size)
    skynet.trash(msg, size)  --这里需要保证内存被释放
    if not ok then 
        errlog(errmsg)
    end
end


function handler.req_all_players(uid, msg, game_session) 
    local all_players = {}
    for i, player_data in pairs(player_data_list) do
        --local p_uid = player_data.uid
        local player_info = { 
            uid = player_data.uid, 
            name = player_data.name or "", 
            coins = player_data.coins, 
            icon = player_data.icon or "", 
            sex = player_data.sex, 
        }
        table_insert(all_players, player_info)
    end         

    send_to_gateway(uid, game_session, "brnn.RSP_ALL_PLAYERS", { players = all_players })

    return true
end


function handle_lua_req(session, source, action, ...)
    --dbglog("internal request", action, ...)
    local f = internal[action]
    if f then
        skynet.retpack(f(...))
    else
        handler[action](...)
    end
end

function start()
    skynet.register_protocol { 
        name = "client", 
        id = skynet.PTYPE_CLIENT, 
        unpack = skynet.unpack, 
        dispatch = dispatch
    }

    skynet.start(function()
        skynet.dispatch("lua", function(session, source, action, ...)
            handle_lua_req(session, source, action, ...)
        end)

        load_config()
    end)
end

return _ENV